訪問 Windows 窗體控件本質上不是線程安全的。如果有兩個或多個線程操作某一控件的狀態,則可能會迫使該控件進入一種不一致的狀態。還可能出現其他與線程相關的 bug,包括爭用情況和死鎖。確保以線程安全方式訪問控件非常重要。
解決辦法
1、把CheckForIllegalCrossThreadCalls設置為false
在多線程程序中,新創建的線程不能訪問UI線程創建的窗口控件,如果需要訪問窗口中的控件,可以在窗口構造函數中將CheckForIllegalCrossThreadCalls設置為 false
public Form1() { InitializeComponent(); CheckForIllegalCrossThreadCalls = false; }
也可以針對某一控件進行設置,例如:
TextBox.CheckForIllegalCrossThreadCalls = false;
2、利用委托
delegate void SetTextCallBack(string text); private void SetText(string text) { if (this.txt_a.InvokeRequired) { SetTextCallBack stcb = new SetTextCallBack(SetText); this.Invoke(stcb , new object[] { text}); } else { this.txt_a.Text = text; } } private void LoadData() { SetText("測試"); } //窗體加載時,用線程加載數據 private void Frm_ImportManager_Load(object sender, EventArgs e) { ThreadStart ts = new ThreadStart(LoadData); Thread thread = new Thread(ts); thread.Name = "LoadData"; thread.Start(); }
3、使用 BackgroundWorker控件
在應用程序中實現多線程的首選方式是使用 BackgroundWorker 組件。BackgroundWorker 組件使用事件驅動模型實現多線程。輔助線程運行 DoWork 事件處理程序,創建控件的線程運行ProgressChanged 和 RunWorkerCompleted 事件處理程序。注意不要從 DoWork 事件處理程序調用您的任何控件。
下面的代碼示例不異步執行任何工作,因此沒有 DoWork 事件處理程序的實現。TextBox 控件的Text 屬性在 RunWorkerCompleted 事件處理程序中直接設置。
// This event handler starts the form's // BackgroundWorker by calling RunWorkerAsync. // // The Text property of the TextBox control is set // when the BackgroundWorker raises the RunWorkerCompleted // event. private void setTextBackgroundWorkerBtn_Click( object sender, EventArgs e) { this.backgroundWorker1.RunWorkerAsync(); } // This event handler sets the Text property of the TextBox // control. It is called on the thread that created the // TextBox control, so the call is thread-safe. // // BackgroundWorker is the preferred way to perform asynchronous // operations. private void backgroundWorker1_RunWorkerCompleted( object sender, RunWorkerCompletedEventArgs e) { this.textBox1.Text = "This text was set safely by BackgroundWorker."; }
大家可以參考下MSDN:如何對 Windows 窗體控件進行線程安全調用
http://msdn.microsoft.com/zh-cn/visualc/ms171728(VS.85,printer).aspx