C#中BackgroundWorker的使用
阿新 • • 發佈:2020-08-13
一、概述
1、BackgroundWorker 類允許您在單獨的專用執行緒上執行操作,在介面上報告進度,接受介面的控制訊號,返回運算結果。
2、BackgroundWorker 的DoWork程式碼執行在非UI執行緒之上,BackgroundWorker 不跨 AppDomain 邊界進行封送處理。
3、BackgroundWorker 是基於事件的非同步程式設計模式EAP的複雜實現。
二、BackgroundWorker 配置
1、初始化BackgroundWorker
主要需要對BackgroundWorker 繫結一下三個事件:
- 開始工作的事件:DoWork——非UI執行緒執行,不可操作介面控制元件物件
- 完成工作的事件:RunWorkerCompleted——UI執行緒執行
- 工作中重新整理的事件:ProgressChanged——UI執行緒執行
public static void BackgroundWorker1_Init() { BackgroundWorker backgroundWorker1 = new BackgroundWorker(); backgroundWorker1.WorkerReportsProgress = true;//能否報告進度更新。 backgroundWorker1.WorkerSupportsCancellation = true;//是否支援非同步取消 //繫結事件 backgroundWorker1.DoWork += new DoWorkEventHandler(BackgroundWorker1_DoWork); backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(BackgroundWorker1_ProgressChanged); backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(BackgroundWorker1_RunWorkerCompleted);//啟動BackgroundWorker if (backgroundWorker1.IsBusy != true)//判斷BackgroundWorker 是否正在執行非同步操作。 { backgroundWorker1.RunWorkerAsync("object argument");//啟動非同步操作,有兩種過載(有參和無參),將觸發BackgroundWorker.DoWork事件 } }
2、DoWork開始事件
/// <summary> /// 控制代碼sender指向的就是該BackgroundWorker。 /// e.Argument 獲取非同步操作引數的值 /// e.Cancel 是否應該取消事件 /// e.Result 獲取或設定非同步操作結果的值(在RunWorkerCompleted事件可能會使用到) /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private static void BackgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { object value = e.Argument;//獲取RunWorkerAsync(object argument)傳入的值 BackgroundWorker worker = sender as BackgroundWorker; for (int i = 1; i <= 10; i++) { if (worker.CancellationPending == true)//在耗時操作中判斷CancellationPending屬性,如果為true則退出 { e.Cancel = true; break; } else { // 執行耗時操作 System.Threading.Thread.Sleep(1000); worker.ReportProgress(i * 10, "Object userState");// 將觸發BackgroundWorker.ProgressChanged事件,向ProgressChanged報告進度 } } e.Result = "結束"; }
3、RunWorkerCompleted完成事件
當DoWork事件處理完成之後,將會觸發該事件處理工作結果。事件可根據傳入的引數e來區分工作是中止或完成。
/// <summary> /// e.Cancelled指示非同步操作是否已被取消 /// e.Error 指示非同步操作期間發生的錯誤 /// e.Result 獲取非同步操作結果的值,即DoWork事件中,Result設定的值。 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private static void BackgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { //判斷是否使用者手動取消,若程式要支援此處功能,需要程式中有cancel的動作,並在該動作中將e.cancel置為true if (e.Cancelled == true) { //新增使用者手動取消的動作,並在標籤控制元件中進行提示 Console.WriteLine($"操作已經被取消!"); } //判斷是否由錯誤造成意外中止 else if (e.Error != null) { //若發生錯誤,在標籤控制元件中顯示錯誤資訊 Console.WriteLine($"操作發生錯誤!"); } //判斷是否正常結束 else { //新增正常結束之後的收尾動作,並在標籤控制元件中進行提示 Console.WriteLine($"執行結果:{e.Result.ToString()}!"); } }
4、ProgressChanged重新整理事件
更新進度條的進度,此處也可以加入使用者在過程中需要實時重新整理的內容
/// <summary> /// 進度重新整理 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private static void BackgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) { //接收ReportProgress方法傳遞過來的userState string state = (string)e.UserState; //e.ProgressPercentage 獲取非同步操作進度的百分比 Console.WriteLine($"進度:{e.ProgressPercentage.ToString() + "%"};狀態:{state}"); }
5、取消BackgroundWorker
取消BackgroundWorker 需要在DoWork中迴圈檢查BackgroundWorker.CancellationPending是否為true。
//終止 private void BackgroundWorker1_End() { if (backgroundWorker1.WorkerSupportsCancellation == true) { // Cancel the asynchronous operation. backgroundWorker1.CancelAsync(); //請求取消掛起的後臺操作。呼叫該方法將使BackgroundWorker.CancellationPending屬性設定為True。 } }
三、完整的程式碼
using System; using System.ComponentModel; namespace BackgroundWorkerDemo { public class BackgroundWorkerInit { public static void BackgroundWorker1_Init() { BackgroundWorker backgroundWorker1 = new BackgroundWorker(); backgroundWorker1.WorkerReportsProgress = true;//能否報告進度更新。 backgroundWorker1.WorkerSupportsCancellation = true;//是否支援非同步取消 //繫結事件 backgroundWorker1.DoWork += new DoWorkEventHandler(BackgroundWorker1_DoWork); backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(BackgroundWorker1_ProgressChanged); backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(BackgroundWorker1_RunWorkerCompleted); //啟動BackgroundWorker if (backgroundWorker1.IsBusy != true)//判斷BackgroundWorker 是否正在執行非同步操作。 { backgroundWorker1.RunWorkerAsync("object argument");//啟動非同步操作,有兩種過載(有參和無參),將觸發BackgroundWorker.DoWork事件 } } /// <summary> /// 控制代碼sender指向的就是該BackgroundWorker。 /// e.Argument 獲取非同步操作引數的值 /// e.Cancel 是否應該取消事件 /// e.Result 獲取或設定非同步操作結果的值(在RunWorkerCompleted事件可能會使用到) /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private static void BackgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { object value = e.Argument;//獲取RunWorkerAsync(object argument)傳入的值 BackgroundWorker worker = sender as BackgroundWorker; for (int i = 1; i <= 10; i++) { if (worker.CancellationPending == true)//在耗時操作中判斷CancellationPending屬性,如果為true則退出 { e.Cancel = true; break; } else { // 執行耗時操作 System.Threading.Thread.Sleep(1000); worker.ReportProgress(i * 10, "Object userState");// 將觸發BackgroundWorker.ProgressChanged事件,向ProgressChanged報告進度 } } e.Result = "結束"; } /// <summary> /// e.Cancelled指示非同步操作是否已被取消 /// e.Error 指示非同步操作期間發生的錯誤 /// e.Result 獲取非同步操作結果的值,即DoWork事件中,Result設定的值。 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private static void BackgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { //判斷是否使用者手動取消,若程式要支援此處功能,需要程式中有cancel的動作,並在該動作中將e.cancel置為true if (e.Cancelled == true) { //新增使用者手動取消的動作,並在標籤控制元件中進行提示 Console.WriteLine($"操作已經被取消!"); } //判斷是否由錯誤造成意外中止 else if (e.Error != null) { //若發生錯誤,在標籤控制元件中顯示錯誤資訊 Console.WriteLine($"操作發生錯誤!"); } //判斷是否正常結束 else { //新增正常結束之後的收尾動作,並在標籤控制元件中進行提示 Console.WriteLine($"執行結果:{e.Result.ToString()}!"); } } /// <summary> /// 進度重新整理 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private static void BackgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) { //接收ReportProgress方法傳遞過來的userState string state = (string)e.UserState; //e.ProgressPercentage 獲取非同步操作進度的百分比 Console.WriteLine($"進度:{e.ProgressPercentage.ToString() + "%"};狀態:{state}"); } } }View Code
using System; namespace BackgroundWorkerDemo { class Program { static void Main(string[] args) { BackgroundWorkerInit.BackgroundWorker1_Init(); Console.ReadKey(); } } }
執行結果: