from:http://www.th7.cn/Program/net/201306/140033.shtmlphp
Windows 窗體中的控件被綁定到特定的線程,不具有線程安全性。所以,若是從另外一個線程調用控件的方法,那麼必須使用控件的一個 Invoke 方法來將調用封送到適當的線程。該屬性可用於肯定是否必須調用 Invoke 方法,當不知道什麼線程擁有控件時這頗有用。html
若是已經建立控件的句柄,則除了 InvokeRequired 屬性之外,控件上還有四個能夠從任何線程上安全調 用的方法,它們是: Invoke、 BeginInvoke、 EndInvoke 和 CreateGraphics。 在後臺線程上建立控件的句柄以前調用 CreateGraphics 可能會致使非法的跨線程調用。 對於全部其餘方法調用,當從另外一個線程進行調用時,應使用這些 Invoke 方法之一。安全
若是控件句柄尚不存在,則 InvokeRequired 沿控件的父級鏈搜索,直到它找到有窗口句柄的控件或窗體爲止。 若是找不到合適的句柄, InvokeRequired 方法將返回 false。app
這意味着若是不須要 Invoke(調用發生在同一線程上),或者若是控件是在另外一個線程上建立的但還沒有建立控件的句柄,則 InvokeRequired 能夠返回 false。函數
若是還沒有建立控件的句柄,您就不能簡單地在控件上調用屬性、方法或事件。這可能致使在後臺線程上建立控件的句柄,從而隔離不帶消息泵的線程上的控件並使應用程序不穩定。ui
當 InvokeRequired 在後臺線程上返回 false 時,您也能夠經過檢查 IsHandleCreated 的值來避免這種狀況。 若是還沒有建立控件句柄,您必須等到控件句柄已建立,才能調用 Invoke 或 BeginInvoke。 一般,僅當在應用程序主窗體的構造函數中建立了後臺線程時(如同在 Application.Run(new MainForm()) 中),在已經顯示窗體或取消 Application.Run 以前,纔會發生這種狀況。 url
一種解決方案是等到已經建立了窗體的句柄,而後啓動後臺線程。經過調用 Handle 屬性強制建立句柄,或者等待 Load 事件啓動後臺進程。spa
一種更好的解決方案是使用 SynchronizationContext 返回的 SynchronizationContext,而不是使用控件進行線程間封送處理。——MSDN
線程
關於這方面一個更容易的解釋以及例子(參考連接:關於invokeRequired與invoke):code
而關於InvokeRequired與Invoke是個老生常談的問題,通常標準寫法爲(圖片截圖來自:Avoiding InvokeRequired,下同):
這種方式的好處就是能在.NET 1.0+上正常運行,可是若是存在不少控件的話,就會存在這樣不少代碼(大量定義委託)。
而在.NET 2.0上,能夠採用匿名委託和MethodInvoker,簡化代碼寫法,關於
MethodInvokerMSDN上的定義以下:
MethodInvoker 提供一個簡單委託,該委託用於調用含 void 參數列表的方法。 在對控件的 Invoke 方法進行調用時或須要一個簡單委託又不想本身定義時可使用該委託。
或者更簡潔的寫法:
而在.NET 3.5+能夠利用其特性,代碼以下(截圖來在:A Generic Method for Cross-thread Winforms Access)
參考資料:
關於invokeRequired與invoke
Avoiding InvokeRequired
A Generic Method for Cross-thread Winforms Access