タイトル : Re^3: 文字列によるプロパティの参照 投稿日 : 2012/01/20(Fri) 22:19 投稿者 : 魔界の仮面弁士
> 文字列によるプロパティの参照 プロパティ名を文字列で指定してアクセスしたい場合は、CallByName を利用できます。 > ユーザーコントロールは別のソルーションで作っているので 公式には、ソルーションではなくソリューションですね。 プロジェクトだけでなく、ソリューションも分かれているのでしょうか? 最初の質問を見て、UserControl も同じEXE内で作られているかと誤読していました。 > デリゲートにしてもイベントにしても理解して > いないので提案自体を理解できません たとえば、ユーザーコントロール内で Me.Label1.Text = 別フォーム.TextBox1.Text という代入操作を行いたいとします。 しかし、ユーザーコントロールは別のアセンブリになっているみたいですし、 上記のように、フォームのインスタンスを決め打ちにすることは難しいですよね。 これをイベントを使って実装する場合、たとえばユーザーコントロール側に、 Public Event RequestText As EventHandler(Of RequestTextEventArgs) のようなイベント(と RequestTextEventArgs クラス)を用意し、 これを通じてデータを貰うようにします。 データを渡す側となる別フォーム側では、そのイベントに応えるために Private WithEvents foo As MyUserControl Private Sub foo_RequestText(sender As Object, e As RequestTextEventArgs) Handles foo.RequestText e.LabelText = Me.TextBox1.Text End Sub のように記述します。変数 foo には、通信先となるユーザーコントロールの インスタンスを予めセットしておきます。 そうするとユーザーコントロール側は、いままで Me.Label1.Text = 別フォーム.TextBox1.Text と書いていた(書こうとしていた)部分を Dim arg As New RequestTextEventArgs("初期値") RaiseEvent RequestText(Me, arg) Me.Label1.Text = arg.LabelText のように差し替えることで、データの受け渡しができます。 用意したイベントが利用されなかった場合には、単に初期値が 表示されるだけなので、別フォームの有無に左右されませんし、 また、データを渡すべきその別フォーム側の処理が複雑化して、 If CheckBox1.Checked Then e.LabelText = Me.TextBox1.Text Else e.LabelText = Me.TextBox2.Text End If のように修正されることになっても、ユーザーコントロール側を手直しせずに済みます。 > Interfaceを用意するとは、つまり間に仲介を入れるって事ですよね? こちらの手法も、もう少し具体的に書いてみると: たとえば、ユーザーコントロール上の PictureBox に渡す画像が、 別フォームの PictureBox から自動転記されるようにするのだとします。 その場合に、 Public Interface IRequestImage Function GetImage() As Image End Interface というインターフェイスを用意し、それを「別フォーム」に Implements して GetImage メソッドを実装しておきます。 そうすると、OpenForms 経由で取り出す際には、 For Each f As Form In Application.OpenForms Dim obj As IRequestImage = TryCast(f, IRequestImage) If obj IsNot Nothing Then Me.PictureBox1.Image = obj.GetImage() End If Next のように、そのインターフェイスを実装しているかどうかを判断基準に できますし、値の取り出しもそのインターフェイスを通じて行えます。 > なぜ直接では危険になるのでしょう? (あれ、危険って書きましたっけ) まぁ、低レベル操作なので注意は必要でしょうね。 たとえば TextBox1 に対して、デザイナで「Modifiers = Private」に変更した場合、 自フォームからは Me.TextBox1 でアクセスできますが、自フォーム以外からは 「対象フォーム.TextBox1」の構文が使えなくなります。 また、デザイナで「GenerateMember = False」にしていた場合には、 自フォームでさえ Me.TextBox1 でアクセスできなくなります。 しかし Controls 経由だと、それらにもアクセスされてしまいます。 極端な話、外部からコントロールを削除したり追加することさえできるわけで、 フォーム側が想定していなかった動作になってしまうこともあります。もちろん、 そのような使い方はしないと思いますが、カプセル化という点からみると、 あまり積極的には使わない方が良いとは思いますよ。 > プロパティを読むだけなの直接ででいいと思うんです。 たとえば、上記の Interface を使ったコードで、ユーザーコントロール側の obj.GetImage() となっている部分を、直接対象コントロールのプロパティを読み取るように DirectCast(fm.Controls("PictureBox1"), PictureBox).Image に変更したとしても、値を取り出すことはできます。 しかしタイプセーフではないため、指定するコントロール名をスペルミスしても 検出できませんし、コントロールの制御方法がユーザーコントロール側に 委ねられるため、各フォーム側のコントロール構成を変更しずらくなります。 しかし Interface/Event/Delegate 等を通じて処理する方法だと、 コントロールの制御は、情報を提供するフォーム自身に書かれるため、 こうした問題は発生しませんし、別フォーム側の改修があっても、 その修正範囲がユーザーコントロール側にまで及ばずに済みます。 ただ、常にそうした実装が優れているかというと、それはやはりケースバイケースとなります。 データバインド(ListBox の DisplayMember や ValueMember など)などのように、 文字列でのプロパティアクセスが必要になるケースもありますので。 > 他のフォームと比較して描画を変えて欲しいと要望があり それは、どのような比較処理なのでしょうか。 たとえば、各フォームのコントロール構成や処理内容がほぼ一定であるような場合には、 先の Interface 案や イベント案だと、わざわざ同じ処理を各フォームに 繰り返し実装していくことになるため、かえって面倒になることもあるかと思います。 そうした場合には、ユーザーコントロール側に処理を書くのではなく、 中継役となる『拡張プロバイダー』を用意する手法もあります。 http://msdn.microsoft.com/ja-jp/library/ms171835.aspx これなら、利用者側はフォームに貼ってデザイン時設定するだけで済みますので、 利用者側の作業を軽減できます。もちろん、最初に中継処理を実装する手間は必要ですが。 |