|
2020/11/28(Sat) 11:27:09 編集(投稿者)
■No96479 (心身 さん) に返信 > バックグラウンドスレッドは複数走らすことができるのに対し > GUIスレッドはフォームを複数もっていたとしても、一つしか走らすことができません。
認識としてはそれでよいと思います。 それぞれの UI スレッドは独立しており、スレッドを跨いだ操作は既定で禁止されています。
ただし、アプリ内のメッセージループは一つだけとは限りません。 スプラッシュスクリーンだとか、非同期通信モジュールの通知ダイアログのように、 一つのアプリ内で複数の UI スレッドが存在することもあります。
void button1_Click(object sender, EventArgs e) { button1.Text = "変えてやる!"; // こっちは成功する anotherFormButton.Text = "変えてみたい"; // こっちはどうだろう? }
anotherFormButton が、自フォームから呼び出したフォーム上のボタンならば 何の問題もありません。button1 と同様に書き換えられます。
しかし button1 と anotherFormButton が異なる UI スレッドに所属していた場合、 既定の設定では、anotherFormButton への操作が InvalidOperationException で停止します。
このような場合は、InvokeRequired で問い合わせて判断します。
void button1_Click(object sender, EventArgs e) { button1.Text = "変えてやる!"; // こっちは成功する if (anotherFormButton.InvokeRequired) { // 別スレッドだったので、相手先のスレッドに作業を依頼 anotherFormButton.Invoke(new MethodInvoker(() => anotherFormButton.Text = "変えてみたい")); } else { // 同一スレッドなので、自分で作業できる anotherFormButton.Text = "変えてみたい"; } }
この時、『anotherFormButton.InvokeRequired』のプロパティ呼び出しを 「InvokeRequired」「this.InvokeRequired」「button1.InvokeRequired」などと書いてはいけません。 (Invoke や BeginInvoke も同様です)
一方、this と button1 が同一の UI スレッドであるため、 this.InvokeRequired と button1.InvokeRequired は同一の意味を持ちます。
if (this.InvokeRequired) { // this.InvokeRequired も button1.InvokeRequired も false になる Invoke(new MethodInvoker(() => button1.Text = "変えてみせる")); } else { // 常にこっちが呼び出される button1.Text = "変えてみせる"; }
もちろん、button1_Click 内で button1 を操作する場合には、 そもそも InvokeRequired 判定自体が不要です。
> Begininvokeやinvoke BeginInvoke や Invoke 、ですね。
> の頭にフォームクラスを引数として受け取る意味がないように思います。 (Begin)Invoke は、Form クラスに実装されたメンバーではなく、 その親クラスである Control クラスにて実装されています。
Form であれ Button であれ Label であれ、どの Control の Invoke を呼び出したとしても、 同じ UI スレッドに所属するコントロールである場合には、振る舞いは同一です。
|