C#中子線程改變主線程控件:invokeRequired屬性和invoke()方法


C#中禁止跨線程直接訪問控件,InvokeRequired是為了解決這個問題而產生的,當一個控件的InvokeRequired屬性值為真時,說明有一個創建它以外的線程想訪問它。此時它將會在內部調用new MethodInvoker(LoadGlobalImage)來完成下面的步驟,這個做法保證了控件的安全。

在設計中為了讓界面與邏輯分離,我的做法是使用事件,界面只要響應事件來處理界面的顯示就行了。而事件在邏輯處理中可能由不同的線程引發,這些事件的響應方法在修改界面中的控件內容時便會引發一個異常。

這時就用到了Control.InvokeRequired 屬性 與Invoke方法。

獲取一個值,該值指示調用方在對控件進行方法調用時是否必須調用 Invoke 方法,因為調用方位於創建控件所在的線程以外的線程中。 

如果控件的 Handle 是在與調用線程不同的線程上創建的(說明您必須通過 Invoke 方法對控件進行調用),則為 true;否則為 false。

Windows 窗體中的控件被綁定到特定的線程,不具備線程安全性 。因此,如果從另一個線程調用控件的方法,那么必須使用控件的一個 Invoke 方法來將調用封送到適當的線程。該屬性可用於確定是否必須調用 Invoke 方法,當不知道什么線程擁有控件時這很有用。

首先定義一個委托,與這個事件處理函數的簽名一樣委托,當然直接使用該事件的委托也是可以的,如:

private delegate void InvokeCallback(string msg);

然后就是判斷這個屬性的值來決定是否要調用Invoke函數:

void  m_comm_MessageEvent( string  msg)
{
    if (txtMessage.InvokeRequired)
    {
        InvokeCallbackmsgCallback = new InvokeCallback(m_comm_MessageEvent);
      txtMessage.Invoke(msgCallback, new object[] { msg } );
    } 
    else 
    {
        txtMessage.Text  =  msg;
    } 
}            

說明:這個函數就是事件處理函數,txtMessage是一個文本框。

這樣就做到了窗體中控件的線程安全性。

InvokeRequired 當前線程不是創建控件的線程時為true

比如你可以自己開一個Thread,或使用Timer的事件來訪問窗體上的控件的時候,在線程中窗體的這個屬性就是True的。

簡單的說,如果有兩個線程,Thread A和Thread B,並且有一個Control c,是在Thread A里面new的。

那么在Thread A里面運行的任何方法調用c.InvokeRequired都會返回false。

相反,如果在Thread B里面運行的任何方法調用c.InvokeRequired都會返回true。

是否是UI線程與結果無關。(通常Control所在的線程是UI線程,但是可以有例外)

也可以認為,在new Control()的時候,control用一個變量記錄下了當前線程,在調用InvokeRequired時,返回當前線程是否不等於new的時候記錄下來的那個線程。

本文轉載於:鏈接


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM