別スレッドからフォームのコントロールを操作する その1

Windowsフォームアプリケーションで、重たい処理をさせたい場合、メインスレッドとは別のスレッドを作って、そっちに処理させたいわけですよ。

ところが.NETではフォームのコントロールの操作は、フォームを所有しているスレッドからしか行えないらしく、別スレッドからコントロール操作をすると例外が発生して落ちてしまう。

とういわけで、メインスレッドに「このコントロールをいじって下さい」みたいなお願いをする必要があるわけだけど、そこで登場するのがdelegateという機能。

System.Windows.Forms.Control.Invokeというメソッドがあり、こいつにDelegateオブジェクトを渡してやるとControlを所有するスレッド上でそのDelegateを実行してくれる。コントロールを操作するメソッドをDelegateにしてやればいいらしい。

[frmMain.cs] //エラーになる版
...
private void doSomething()
{
 // 重い処理を別スレッドで処理
  Thread t = new Thread(new ThreadStart(doHeavyWork));
  t.Start();
}

private void doHeavyWork()
{
 // 重い処理を別スレッドで処理
  txtName.SetFocus(); //エラー!
}
[frmMain.cs] //ちゃんと動く版
...
delegate void FocusDelegate(); // Delegateの宣言

private void doSomething()
{
  Thread t = new Thread(new ThreadStart(work));
  t.Start();
}

private void work()
{
  Invoke( new FocusDelegate(txtName.Focus()) ); // おk
}

DelegateというのはJAVAで言えば無名クラスを作って処理を委譲させるようなもんだろうか。いちいちDelegateメソッドを宣言してやらないといけないのがちょっと面倒。

と思ったらMethodInvoker デリゲート (System.Windows.Forms)とか匿名メソッド (C#)なんて機能があるのな。また明日調べよう。