從0自學C#02--子線程訪問主線程(UI線程)控制項

來源:互聯網
上載者:User
如果使用多執行緒來提高 Windows 表單應用程式的效能,則你必須確保以安全執行緒的方式調用控制項。

訪問 Windows 表單控制項不是本身就安全執行緒的。如果有兩個或兩個以上線程操作控制項的狀態,則可能迫使該控制項處於不一致狀態。可能出現其他與線程相關的 bug,例如競爭條件和死結。請務必確保以安全執行緒的方式訪問控制項。

1.初學者常常遇到的問題

從未使用 Invoke 方法建立控制項的線程調用控制項是不安全的。下面是一個非安全執行緒的調用樣本。運行時會引發 InvalidOperationException 訊息,報錯“從並未建立該控制項的線程訪問該控制項 控制項名稱”。

// This event handler creates a thread that calls a // Windows Forms control in an unsafe way.private void setTextUnsafeBtn_Click(    object sender,     EventArgs e){    this.demoThread =         new Thread(new ThreadStart(this.ThreadProcUnsafe));    this.demoThread.Start();}// This method is executed on the worker thread and makes// an unsafe call on the TextBox control.private void ThreadProcUnsafe(){    this.textBox1.Text = "This text was set unsafely.";}


2.解決方案

如需對 Windows 表單控制項進行安全執行緒的調用。

①查詢控制項的 InvokeRequired 屬性。

②若 InvokeRequired 返回 true,則用實際調用控制項的委託來調用 Invoke。

③若 InvokeRequired 返回 false,則請直接調用控制項。

這裡分同步執行委託和非同步執行委託。

在以下程式碼範例中,在 ThreadProcSafe 方法中實現了安全執行緒的調用,該方法由後台線程執行。若 TextBox 控制項的 InvokeRequired 返回 true,則 ThreadProcSafe 方法建立一個 SetTextCallback 執行個體並將其傳遞到表單的 Invoke 方法。這導致在建立了 SetText 控制項的線程上調用 TextBox 方法,並且在該線程上下文中直接設定 Text 屬性。

// This event handler creates a thread that calls a // Windows Forms control in a thread-safe way.private void setTextSafeBtn_Click(    object sender,     EventArgs e){    this.demoThread =         new Thread(new ThreadStart(this.ThreadProcSafe));    this.demoThread.Start();}// This method is executed on the worker thread and makes// a thread-safe call on the TextBox control.private void ThreadProcSafe(){    this.SetText("This text was set safely.");}// This delegate enables asynchronous calls for setting// the text property on a TextBox control.delegate void SetTextCallback(string text); // This method demonstrates a pattern for making thread-safe// calls on a Windows Forms control. //// If the calling thread is different from the thread that// created the TextBox control, this method creates a// SetTextCallback and calls itself asynchronously using the// Invoke method.//// If the calling thread is the same as the thread that created// the TextBox control, the Text property is set directly. private void SetText(string text){    // InvokeRequired required compares the thread ID of the    // calling thread to the thread ID of the creating thread.    // If these threads are different, it returns true.    //this.textBox1.InvokeRequired will be replaced by    //this.InvokeRequired, if want to set many controls'     //attribute or text.    if (this.textBox1.InvokeRequired)// or this.InvokeRequired    {           SetTextCallback d = new SetTextCallback(SetText);        this.Invoke(d, new object[] { text });    }    else    {        this.textBox1.Text = text;    }}

3.BackgroundWorker組件

在應用程式中實現多線程的首選方式是使用 BackgroundWorker 組件。 BackgroundWorker 組件為多執行緒使用事件驅動模型。後台線程運行你的 DoWork 事件處理常式,建立了你的控制項的線程運行 ProgressChanged 和 RunWorkerCompleted 事件處理常式。你可以從 ProgressChanged 和 RunWorkerCompleted 事件處理器中調用控制項。

①建立一種方法來進行你想在後台線程中進行的工作。不要調用由此方法中的主線程所建立的控制項。

②建立一種方法來報告後台工作結束後的後台工作結果。 在此方法中可以調用主線程建立的控制項。

③將步驟 1 中建立的方法綁定到 DoWork 執行個體中的 BackgroundWorker 事件,並將步驟 2 中建立的方法綁定到同一執行個體的 RunWorkerCompleted 事件。

④若要啟動後台線程,請調用 RunWorkerAsync 執行個體的 BackgroundWorker 方法。

在以下程式碼範例中,DoWork 事件處理常式使用 Sleep 來類比需要花費一些時間的工作。它不會調用該表單的 TextBox 控制項。TextBox 控制項的 Text 屬性直接在 RunWorkerCompleted 事件處理常式中設定。

// This BackgroundWorker is used to demonstrate the // preferred way of performing asynchronous operations.private BackgroundWorker backgroundWorker1; // 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.";}

也可通過使用 ProgressChanged 事件來報告背景工作的進度。如需包含該事件的樣本,請參閱 BackgroundWorker。

以上就是 從0自學C#02--子線程訪問主線程(UI線程)控制項的內容,更多相關內容請關注topic.alibabacloud.com(www.php.cn)!

  • 相關文章

    聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.