訪問 Windows 窗體控件本質(zhì)上不是線程安全的。如果有兩個或多個線程操作某一控件的狀態(tài),則可能會迫使該控件進(jìn)入一種不一致的狀態(tài)。還可能出現(xiàn)其他與線程相關(guān)的 bug,包括爭用情況和死鎖。確保以線程安全方式訪問控件非常重要。
.NET Framework 有助于在以非線程安全方式訪問控件時檢測到這一問題。在調(diào)試器中運行應(yīng)用程序時,如果創(chuàng)建某控件的線程之外的其他線程試圖調(diào)用該控件,則調(diào)試器會引發(fā)一個 InvalidOperationException,并提示消息:“從不是創(chuàng)建控件 control name 的線程訪問它。”
有三種方法可以從線程訪問Win窗體的控件:非線程安全方式;線程安全調(diào)用;使用BackgroundWorker進(jìn)行的線程安全調(diào)用。其中,只有線程的安全調(diào)用可以宏觀并行處理。(另外兩種方式都是在線程運行時接受命令,但在線程執(zhí)行完以后才執(zhí)行)。
一:對Windows窗體控件的非線程安全調(diào)用
該方式是從輔助線程直接調(diào)用。調(diào)用應(yīng)用程序時,調(diào)試器會引發(fā)一個InvalidOperationException,警告對控件的調(diào)用不是線程安全的。
可以通過將 CheckForIllegalCrossThreadCalls 屬性的值設(shè)置為 false 來禁用此異常。這會使控件以與在 Visual Studio 2003 下相同的方式運行。
具體做法如下:





二:對Windows窗體控件的線程安全調(diào)用
對窗體控件的線程安全調(diào)用需要用委托的方式。
主要思路:
1、查詢控件的 InvokeRequired 屬性。
2、如果 InvokeRequired 返回 true,則使用實際調(diào)用控件的委托來調(diào)用 Invoke。
3、如果 InvokeRequired 返回 false,則直接調(diào)用控件。
例子:在TextBox控件中輸出相應(yīng)的信息,SetText為textbox的內(nèi)容設(shè)置方法,SetTextDelegate的委托類型封裝 SetText方法。TextBox控件的InvokeRequired返回true是,SetText方法創(chuàng)建SetTextDelegate的一個實 例,并調(diào)用窗體的Invoke方法。是的SetText方法被創(chuàng)建TextBox控件的線程調(diào)用。













































三、使用 BackgroundWorker 進(jìn)行的線程安全調(diào)用
在應(yīng)用程序中實現(xiàn)多線程的首選方式是 使用 BackgroundWorker 組件。BackgroundWorker 組件使用事件驅(qū)動模型實現(xiàn)多線程。輔助線程運行 DoWork 事件處理程序,創(chuàng)建控件的線程運行 ProgressChanged 和 RunWorkerCompleted 事件處理程序。注意不要從 DoWork 事件處理程序調(diào)用您的任何控件。
下面的代碼示例不異步執(zhí)行任何工作,因此沒有 DoWork 事件處理程序的實現(xiàn)。TextBox 控件的 Text 屬性在 RunWorkerCompleted 事件處理程序中直接設(shè)置。












