以前の記事「【VB.NET】スレッドからフォームのコントロールを扱う」の応用。

進行状況を表示する必要がある処理をフォームとは、別のクラスにすることは多い。
その場合に実装しているクラスからプログレスバー等を操作する場合の方法について説明する。

以下の2つの技法の組み合わせで実現できる。
 ・「【VB.NET】スレッドからフォームのコントロールを扱う
 ・「【VB.NET】他のフォームに引数を受け渡す方法
  →フォームコントロールを引数として渡す方法を利用する。

以下、サンプル。
《Form1.vb》
Public Class Form1
Inherits System.Windows.Forms.Form
:(中略)

'スレッドの作成
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()
Dim oClass1 As New Class1(Me)
oClass1.WriteTextBox()
End Sub

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

《Class1.vb》
Public Class Class1
'コントロールを扱うためのデリゲート宣言
Delegate Sub SetTextBox1Delegate(ByVal Value As String)

'デリゲート宣言をデータ型とした変数を作成
Private TextBox1Delegate As SetTextBox1Delegate

'フォームの参照を保持する
Private _Form1 As Form1

'コンストラクタ
Public Sub New(frm As Form)
_Form1 = CType(frm, Form1)
TextBox1Delegate = New _
SetTextBox1Delegate(AddressOf _Form1.SetTextBox1)
End Sub

'テキストボックスに値を設定する
Public Sub WriteTextBox()
For idx As Integer = 0 To 9
_Form1.Invoke(TextBox1Delegate, New Object() {idx.ToString()})
'Invokeを以下に置き換える
'Me.TextBox1.Text = idx.ToString()
System.Threading.Thread.Sleep(500)
Next idx
End Sub
End Class

一つのクラス内だけで完結する処理のサンプルとの違いは、以下の通り。
1.デリゲートに関する宣言は、メソッドを利用したいクラスで行う。
2.コントロールの操作用メソッドは、アクセス修飾子を"Public"や"Friend"にする。
 →"Private"では、他のクラスから参照できない。
3.フォームのInvokeメソッドを利用するため、利用したいフォームのコントロールを取得する必要がある。
 →上記サンプルでは、コンストラクタの引数として受け取っている。

【補足事項】
・デリゲートのインスタンス化は、コンストラクタやメソッド内で行う。
 →インスタンス変数宣言時に同時にインスタンス化すると実行時エラーが発生する。