1. 程式人生 > >BackgroundWorker 實現多執行緒操作

BackgroundWorker 實現多執行緒操作

背景介紹

  在做程式的過程中,我們很可能遇到這樣的情況:當我們執行一個比較耗時的操作,即介面載入資料量略大的時,在該操作未完成之前再去操作介面,就會出現停止響應的情況,這稱為介面假死狀態,那一個小圓圈轉呀轉的,想必大家看著就頭疼。當然這是一個非常影響使用者體驗度的地方。

  怎麼做出一個能夠及時響應的使用者介面呢?—多執行緒操作。

  引入BackgroundWorker元件:BackgroundWorker是·net裡用來執行多執行緒任務的控制元件,它允許程式設計者在一個單獨的執行緒上執行一些操作。

BackgroundWorker元件

  常用方法

  1.RunWorkerAsync 開始執行後臺操作。引發 DoWork 事件

  2.CancelAsync 請求取消掛起的後臺操作。

  注意:這個方法是將 CancellationPending 屬性設定為 true,並不會終止後臺操作。在後臺操作中要檢查

CancellationPending 屬性,來決定是否要繼續執行耗時的操作。

  3.ReportProgress引發 ProgressChanged 事件。

  常用屬性

  1.CancellationPending 指示應用程式是否已請求取消後臺操作。只讀屬性,預設為 false,當執行了 CancelAsync 方法後,值為 true。

  2.WorkerSupportsCancellation指示是否支援非同步取消。要執行 CancelAsync 方法,需要先設定該屬性為 true。

  3.WorkerReportsProgress指示是否能報告進度。要執行 ReportProgress 方法,需要先設定該屬性為 true。

  常用事件

  1.DoWork 呼叫 RunWorkerAsync 方法時發生。

  2.RunWorkerCompleted後臺操作已完成、被取消或引發異常時發生。

  3.ProgressChanged呼叫 ReportProgress 方法時發生。

  注意:在 DoWork 事件處理程式中不操作任何使用者介面物件。而應該通過 ProgressChanged 和RunWorkerCompleted 事件與使用者介面進行通訊。

  如果想在 DoWork 事件處理程式中和使用者介面的控制元件通訊,可在用 ReportProgress 方法。ReportProgress(int percentProgress, object userState),可以傳遞一個物件。ProgressChanged 事件可以從引數ProgressChangedEventArgs 類的UserState 屬性得到這個資訊物件。這個事件也可以實現進度條功能,把任務的進度實時呈現給使用者。

  簡單的程式用BackgroundWorker 比 Thread 方便,Thread中和使用者介面上的控制元件通訊比較麻煩,需要用委託來呼叫控制元件的 Invoke 或BeginInvoke 方法,沒有 BackgroundWorker 方便。

BackgroundWorker Demo

  1. namespace BackgroundWorkerTest  
  2. {  
  3.     public partial class Form1 : Form  
  4.     {  
  5.         public Form1()  
  6.         {  
  7.             InitializeComponent();  
  8.             backgroundWorker1.WorkerReportsProgress = true;//報告完成進度  
  9.             backgroundWorker1.WorkerSupportsCancellation = true;//允許使用者終止後臺執行緒  
  10.         }  
  11.         //開始按鈕  
  12.         private void button1_Click(object sender, EventArgs e)  
  13.         {  
  14.             if (!backgroundWorker1.IsBusy )//判斷backgroundWorker1是否正在執行非同步操作  
  15.             {  
  16.                 //backgroundWorker1.RunWorkerAsync();  
  17.                 backgroundWorker1.RunWorkerAsync(1000);//開始執行後臺操作,呼叫DoWork事件  
  18.             }  
  19.         }  
  20.         //DoWork事件宣告要執行的耗時操作  
  21.         private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)  
  22.         {  
  23.             e.Result = ListNumber(backgroundWorker1, e);//運算結果儲存在e.Result中  
  24.         }  
  25.         bool ListNumber(object sender, DoWorkEventArgs e)  
  26.         {  
  27.             int num=(int)e.Argument;//接收傳入的引數  
  28.             for (int i = 1; i <= num; i++)  
  29.             {  
  30.                 if (backgroundWorker1.CancellationPending)//判斷是否請求了取消後臺操作  
  31.                 {  
  32.                     e.Cancel=true;  
  33.                     return false;  
  34.                 }  
  35.                 //backgroundWorker1.ReportProgress(i * 100 / num);  
  36.                 backgroundWorker1.ReportProgress(i * 100 / num,i);//報告完成進度  
  37.                 Thread.Sleep(0);//後臺執行緒交出時間片  
  38.             }  
  39.             return true;  
  40.         }  
  41.         private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)  
  42.         {  
  43.             //將完成進度資料傳給進度條  
  44.             progressBar1.Value = e.ProgressPercentage;  
  45.             label1.Text = e.ProgressPercentage + "%";  
  46.             //將中間計算結果在ListBox控制元件中顯示出來  
  47.             listBox1.Items.Add(e.UserState);  
  48.         }  
  49.      Private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)  
  50.      {  
  51.           if (!e.Cancelled && e.Error==null)  
  52.           {  
  53.               MessageBox.Show("處理完成了嗎?  " + e.Result);  
  54.           }  
  55.           else//如果取消後臺執行緒或發生了異常  
  56.           {  
  57.               MessageBox.Show("處理完成了嗎?  false");  
  58.           }  
  59.       }  
  60.         //取消按鈕  
  61.         private void button2_Click(object sender, EventArgs e)  
  62.         {  
  63.             if (backgroundWorker1.WorkerSupportsCancellation==true)  
  64.             {  
  65.                 backgroundWorker1.CancelAsync();//取消後臺操作  
  66.                 backgroundWorker1.Dispose();//釋放資源  
  67.             }  
  68.         }  
  69.     }  
  70. }  

總結:

  使用backgroundWorker實現多執行緒大致的步驟是:

  1、繫結執行緒,設定屬性

  2、呼叫BackgroundWorker的RunWorkerAsync方法(可以傳遞引數),它將呼叫DoWork事件

  3、宣告DoWork事件的委託方法,在後臺執行耗時的操作

  4、在耗時操作中判斷CancellationPending屬性,如果為false則退出

  5、如果要向用戶介面傳送資訊,則呼叫BackgroundWorker的ReportProgress方法,它將呼叫ProgressChanged事件(可以將改變通過object型別傳遞)

  6、在ProgressChanged事件的響應程式碼中將改變呈現給使用者,類似進度條。

  7、如果需要取消耗時操作,則呼叫BackgroundWorker的CancelAsync方法,需要和步驟3一起使用

  總的來說就是用backgroundWorker元件來新建一個執行緒,把耗時的部分放到這個執行緒中在後臺進行處理。這樣就不會影響介面的正常使用。舉個通俗的例子,在我們開啟一個網頁的時候,先載入完的總是文字,然後圖片在慢慢出現。這就是執行緒的應用,網頁開啟的時候先呈現出文字,供使用者瀏覽,然後把載入圖片放到一個單獨的執行緒中,非同步的在後臺執行,執行完畢後把圖片呈現出來。

  這樣就避免了一開啟介面就載入大量資訊,而造成的介面假死狀態,大大提高了使用者體驗度。