What is InvokeRequired?


        delegate void SetTextCallback(Control ctl, String str);// 設置textbox.text
        delegate string GetTextCallback(Control ctl); //讀取textbox.text

        public string gettext(Control ctl)
        {
            if (this.InvokeRequired) //InvokeRequired required compares the thread ID of the // calling thread to the thread ID of the creating thread. // If these threads are different, it returns true.
            {
                GetTextCallback d = new GetTextCallback(gettext);
                string x;
                x = (string)this.Invoke(d, new Object[] { ctl });
                return x;
            }
            else
            {
                return ctl.Text;
            }

        }

        public void SetText(Control ctl, String str)
        {
            if (this.InvokeRequired)
            {
                SetTextCallback s = new SetTextCallback(SetText);
                this.Invoke(s, ctl, str);
            }
            else
            {
                ctl.Text = str;
            }
        }



from https://so-zou.jp/software/tech/programming/c-sharp/thread/thread-safe-call.htm



独自の実装

コントロールをスレッド セーフとするには、次のように呼び出します。
  1. コントロールが破棄されていないか、IsDisposedプロパティで確認する。
  2. コントロールのInvokeRequiredプロパティから、スレッドが異なるか確認する
  3. コントロールと同一のスレッドで実行されるように処理する。
    • スレッドが異なる … コントロールと同一のスレッドで実行されるように、delegateを使用してInvoke()メソッドから呼び出す。
    • スレッドが同一 … コントロールを直接呼び出す。
破棄されているコントロールへアクセスすると、ObjectDisposedException例外が発生します。
スレッドを考慮をせずコントロールにアクセスすると、「有効ではないスレッド間の操作: コントロールが作成されたスレッド以外のスレッドからコントロール 'control' がアクセスされました。」としてInvalidOperationException例外が発生します。

コントロールのスレッドでの実行

public object Invoke(
    Delegate method
)
Control.Invoke メソッド (Delegate) (System.Windows.Forms) | MSDN
デリゲートを非同期で実行するならば、BeginInvoke()で呼び出します。
public IAsyncResult BeginInvoke(
    Delegate method
)
Control.BeginInvoke メソッド (Delegate) (System.Windows.Forms) | MSDN

サンプルコード

// Windowsフォームコントロールに対して非同期な呼び出しを行うためのデリゲート
delegate void SetTextCallback( TextBox textBox, string text );
private void SetText( TextBox textBox, string text )
{
    // コントロールが破棄されているならば、何もしない
    if (textBox.IsDisposed) return;

    // 呼び出し元のコントロールのスレッドと異なるかを確認する
    if( textBox.InvokeRequired )
    {
        // このブロックは、別スレッドで実行される

        // 同一メソッドへのコールバックを作成する
        SetTextCallback delegateMethod = new SetTextCallback( SetText );

        // コントロールの親のInvoke()メソッドを呼び出すことで、
        //  呼び出し元のコントロールのスレッドでこのメソッドを実行する
        this.Invoke( delegateMethod, new object[] { textBox, text } );
    }
    else
    {
        // このブロックは、同一スレッドで実行される

        // コントロールを直接呼び出す
        textBox.Text = text;
    }
}



留言

熱門文章