tagCANDY CGI VBレスキュー(花ちゃん) の Visual Basic 2010 用 掲示板(VB.NET 掲示板)
VBレスキュー(花ちゃん) の Visual Basic 2010 用 掲示板(VB.NET 掲示板)
[ツリー表示へ]  [ワード検索]  [Home]

タイトル 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

これなら、利用者側はフォームに貼ってデザイン時設定するだけで済みますので、
利用者側の作業を軽減できます。もちろん、最初に中継処理を実装する手間は必要ですが。

- 関連一覧ツリー をクリックするとツリー全体を一括表示します)

古いスレッドにレスはつけられません。