2016年4月11日 星期一

IsHandleCreated, InvokeRequired 與 Invoke 的關係

要存取 Windows Forms Controls 就必須考慮 Thread-Safe的問題 (參閱: 這裡)。如果 InvokeRequired 是 True,就必須使用 Invoke method 來保證 Thread-Safe。

然而,要使用 Invoke method,必須確定到這個 Form 或是 Control 已經擁有 '視窗控制代碼' (window handle)。
在下列的情況下,Handle 才會存在:
  • Form/Control 已經實體化( instantiated )且初始化 (initialized, first shown)
  • Form 還沒被 closed (i.e., handle 還沒被 disposed)
** 要注意的是,使用InvokeRequired 判斷是否為 cross-thread 並不正確! 因為 InvokeRequired 在下列2種情況會回傳 False:
  1. 相同 thread (表示不需要 Invoke)
  2. Form/Control 沒有 handle (沒有 handle 就不可能 Invoke)
也就是說,InvokeRequired  只能判斷要不要 Invoke!

若要使用InvokeRequired 判斷 cross-thread,必須排除 handle 不存在所造成的影響。
比較好的做法是: 使用 InvokeRequired 之前,先判斷 IsHandleCreated 為True

[例如]:
private delegate void SetTextDelegate(string text, Color color, Font font);

private void SetText(string text, Color color, Font font)
{
            if (IsHandleCreated)
            {
                 // 已經排除沒有 handle 的情況
                 // 所以可用InvokeRequired 判斷是否為 cross-thread
                if (InvokeRequired)                
                {
                    SetTextCallback d = new SetTextCallback(SetText);
                    Invoke(d, new object[] { text, color, font });
                }
                else // use the RichTextBox control directly
                {
                    txtLogging.AppendText(text);
                    txtLogging.SelectionColor = color;
                    txtLogging.SelectionFont = font;
                 }
            }
}

相關連結:
Invoke or BeginInvoke cannot be called on a control until the window handle has been created


沒有留言:

張貼留言