非同期デリゲートからGUIにアクセスする場合のイディオム
.NET2.0では、Windowsフォーム内のコントロール(System.Windows.Forms.Controlクラスの派生クラス)は、特定のスレッドにバインドされているため、非同期デリゲートなどを経由して他のスレッドからアクセスすると、間違いなく例外が発生する。
System.InvalidOperationException はハンドルされませんでした。
Message="有効ではないスレッド間の操作: コントロールが作成されたスレッド以外のスレッドからコントロール '' がアクセスされました。"
これを避けるためには、Microsoftの言葉を借りると「コントロールの invoke メソッドを使用して、適切なスレッドへの呼び出しをマーシャリングする必要があります。」となるのだが、いまひとつピンとこないし、勝手が良くない。
よく使うパターンとして、Control派生クラスにアクセスするロジックを別メソッドとして分離し、そのメソッドと同じ型のデリゲートを用意して、以下のように記述することで例外を防げる。
//メソッドと同じシグネチャを持つデリゲートの定義が必要 private delegate void ResultShowingHandler(object args); //Controlにアクセスするロジックを切り出したメソッド private void ResultShowing(object args) { //非同期処理に対応 if (this.Form1.InvokeRequired) { ResultShowingHandler handler = new ResultShowingHandler(this.ResultShowing); this.Form1.Invoke(handler, new object[] {args}); return; } //Formとその配下のコントロールにアクセスする処理を記述 }
もっと良いパターンはあると思うし、ベタだけど自分用なんで。
いつもそうなんだけど、.NETでの開発を暫くしないでいると、一番先に忘れてしまうのがデリゲートと、特に非同期デリゲート。何度プログラミングしても、何度となく非同期デリゲートのパターンで書いても、半年も放置しておくとすっからかんに忘れてしまう。自分では、記述の仕方や構成が直感的ではないからだ、と勝手に思ってるのだが、単に私の物覚えが悪いのだろう。
なのでメモ。