web-dev-qa-db-ja.com

GUIアプリにC#MethodInvoker.Invoke()を使用する...これでいいですか?

C#2.0とMethodInvokerデリゲートを使用して、GUIアプリケーションがGUIスレッドまたはワーカースレッドからイベントを受信して​​います。

次のパターンを使用して、フォームでイベントを処理します。

private void SomeEventHandler(object sender, EventArgs e)
{
    MethodInvoker method = delegate
        {
            uiSomeTextBox.Text = "some text";
        };

    if (InvokeRequired)
        BeginInvoke(method);
    else
        method.Invoke();
}

このパターンを使用して実際のUIコードを複製することはありませんが、この方法が適切かどうかはわかりません。

特に、ライン

method.Invoke()

呼び出しに別のスレッドを使用しますか、それともGUIスレッドのメソッドへの直接呼び出しに多少変換しますか?

26
Stécy

method.Invoke()呼び出しは、現在実行中のスレッドでデリゲートを実行します。 BeginInvoke(method)を使用すると、デリゲートがGUIスレッドで確実に呼び出されます。

これは、GUIスレッドと他のスレッドの両方から同じメソッドを呼び出すことができる場合に、コードの重複を回避する正しい方法です。

21
CMerat

個人的に私はこの方法が好きです:

private void ExecuteSecure(Action a)
{
    if (InvokeRequired)
        BeginInvoke(a);
    else
        a();
}

そして、次のようなワンライナーを書くことができます:

ExecuteSecure(() => this.Enabled = true);
15
Stephan Ryer

バックグラウンドスレッドを使用していて、Control.IsHandleCreatedがfalseの場合、Control.InvokeRequiredはfalseを返すことに注意してください。アンマネージハンドルの作成をチェックするDebug.Assertでコードを保護します。

5
GregC

WinFormsの場合、Control.Invoke(Delegate)を呼び出すと、UIのtheadのメッセージポンプにメッセージが送信されます。次に、スレッドはメッセージを処理し、デリゲートを呼び出します。処理が完了すると、Invokeはブロックを停止し、呼び出しスレッドがコードの実行を再開します。

2
Samuel

同じスレッドで呼び出しを行います。コードをステップ実行して確認できます。そのアプローチには何の問題もありません。

0
Nick Whaley