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的時候記錄下來的那個線程。
宋興柱(Sindrol):轉載内容,請标明出處,謝謝!
以上隻是個人想法和實踐經驗所得,如果有文字錯誤和文法錯誤,請加以指點!
QQ:247039968
emil:[email protected]
無論是美女的歌聲,還是鬣狗的狂吠,無論是鳄魚的眼淚,還是惡狼的嚎叫,都不會使我動搖