2007年10月22日月曜日

Invokeとdelegate

C#のプログラムを作ってて
忘れるといけないのでまとめ

間違ってたり,補足があったらコメントしていただけると助かります.

あるメソッドAから別のあるメソッドBを呼び出そうとすると
エラーが出る場合がある

例:
private void serialPort1_DataReceived(略)
{
  textBox1.text = "hoge";
}


みたいな感じにすると止まる.
やろうとしてたのはシリアルポートでなにかを受信したら
"hoge"をテキストボックスに表示するというアプリケーションの作成

やれない理由は,メソッドAが動いてるスレッド中にメソッドBを無理やり動かそうとするため
Windowsフォーム上でフォームを作成した場合,そのフォーム自身以外からのアクセスは動作が保障されていないため
まぁ,CheckForIllegalCrossThreadCalls プロパティの値を false に設定すれば動くようにはなるらしい.

が,根本的な解決になっていないのでいろいろ勉強した

使用したのはInvokeとdelegate
で,まぁ
Invokeっていうのは,別スレッドからコントロールを呼び出したときに
そのコントロールの操作を対象のスレッドで実行できるようにするメソッドで
System.Windows.formsに用意されている

delegateは
処理をしたいメソッドを直接書くのではなく,
その引数の型に合ったメソッドに処理の中継をしてくれるやつ

んで,この二つを使ってさっきのやつを書きなおすと

private void serialPort1_DataReceived(略)
{
setText("hoge");
}

delegate void myText(string text);

private void setText(string text)
{
if (this.textBox1.InvokeRequired)
  {
myText d = new myText(setText);
  this.Invoke(d, new object[] { text });
}
else
{
  this.textBox1.Text = text;
}
}

っつう風になります.

んで,
if (this.textBox1.InvokeRequired) は
InvokeRequiredはInvokeが必要かどうかの判定
もっと言うと,同一のスレッドではない場合の処理

myText d = new myText(setText);
this.Invoke(d, new object[] { text });

は,delegateで宣言した myTextクラスのメソッドを宣言して
Invokeしてる
this.Invoke(d, new object[] { text });
               {}内は,delegateで宣言した引数.

で,こんな感じにすれば
setText()は,どこでも動くものになりましたよって感じ

1 件のコメント:

匿名 さんのコメント...

just stopping by to say hello