今回は、VB.NETでスレッドを扱う際にメインスレッドとは異なるスレッドからフォームのコントロールを操作する方法について説明する。

以下、スレッドについての簡単な説明。
 ・プログラムを実行すると、プロセスという単位で管理される。
 ・プロセスには、メインスレッドが必ず生成される。
 ・スレッドを意識しないプログラムの場合、このメインスレッドのみで処理を行うことになる。
 ・メインスレッド以外のスレッドを使って処理することを指す。

Windowsアプリケーションでスレッドを作成した場合、フォームやフォームに配置したコントロールに対する操作は保証されていない。
(ここで言う操作とは、コントロールのメソッドの実行やプロパティの操作を指す)
このような処理を想定通りに動かすためには、以下のような手順が必要となる。
【必要な手順】
 1.フォームクラスで各コントロールに対する操作メソッドを作成する。
 2.Delegate宣言を行う。
  →名前を以下のようにしておくと分かりやすい。
   「項番1で作成したメソッド名 + Delegate」等
 3.項番2で作成したデリゲートを型とした変数を宣言する
  →Newキーワードを付けると、コンストラクタの引数が必要となる。
   "AddressOf デリゲートするメソッド名"を引数に指定する。
  ※デリゲートするメソッド名は、項番1のメソッドとなる。
  →Newキーワードをつけない場合、適切な箇所でインスタンスを生成する必要がある。
   ※必ず、Newキーワードを使ってインスタンス化する必要がある。
 4.フォームコントロールのInvokeメソッドを利用してデリゲートしたメソッドを実行する。

以下、別のスレッドからコントロールを操作するサンプル。
(1つのクラス内だけで完結する処理のサンプル)

《Form1.vb》
Public Class Form1
 Inherits System.Windows.Forms.Form
   :(中略)

 'コントロールを扱うためのデリゲート宣言
 Delegate Sub SetTextBox1Delegate(ByVal Value As String)

 'デリゲート宣言をデータ型とした変数を作成
 Private TextBox1Delegate As _
  New SetTextBox1Delegate(AddressOf SetTextBox1)

 'スレッドの作成
 Public Sub Button1_Clicked(ByVal sender As System.Object, _
  ByVal e As System.EventArgs) Handles Button1.Click

  Dim Thread1 As New System.Threading.Thread( _
   New System.Threading.ThreadStart(AddressOf ThreadA))
  Thread1.IsBackground = True
  Thread1.Start()

  MessageBox.Show("終了", "通知", MessageBoxButtons.OK)
 End Sub

 'スレッドの本体
 Private Sub ThreadA()
  For idx As Integer = 0 To 9
   Me.Invoke(TextBox1Delegate, New Object() {idx.ToString()})
   'Invokeを以下に置き換える
   'Me.TextBox1.Text = idx.ToString()
   System.Threading.Thread.Sleep(500)
  Next idx
 End Sub

 'テキストボックスの値設定(Delegateするメソッド)
 Private Sub SetTextBox1(ByVal Value As String)
  TextBox1.Text = Value
 End Sub
End Class

この程度のプログラムであれば、ThreadAメソッドの"Me.Invoke〜"を"Me.TextBox1〜"に置き換えても動作する。
しかし、複雑な処理の場合にコントロールを直接操作すると、思わぬ動作を引き起こす原因になりかねない。
(先述の通り、コントロールを直接操作する方法は、動作が保証されていない)
そのため、デリゲートとInvokeメソッドを使って操作する方法で実装することをお勧めする。

【補足事項】
・Invokeメソッドの引数は、以下の通り。
 第1引数 … デリゲートしたメソッド
 第2引数 … デリゲートしたメソッドの引数(オブジェクト配列)
・スレッドを扱う場合、デリゲートを扱えるようにしておいた方が良い。
・VB 2005以降は、この方法でコントロールを操作しないと実行時エラーが発生する。
・デリゲートは、メソッド数分必要となる。
・別のクラスからフォームのコントロールを操作する場合には、もう少し工夫が必要。