1. 程式人生 > 實用技巧 >C#中BackgroundWorker的使用

C#中BackgroundWorker的使用

一、概述

  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();
        }
    }
}

執行結果: