[C#] BackgroundWorker

  • 36826
  • 0

摘要:[C#] BackgroundWorker

Introduction

使用 .net  內建的元件去實現非同步作業。當一個作業需要花很長的時間去完成,大都會使用背景處理,

這樣使用者還是可以繼續其他的操作,並且 UI 介面也不會鎖死。

當然,有許多方法可以達到背景作業的效果,這邊使用 backgroundworker 元件測試。


Example

    public partial class Form1 : Form {

        //宣告 BW 變數
        private BackgroundWorker _BW;

        //宣告 _Limit 變數,並且設定初值
        private int _Limit = 100000;

        public Form1() {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e) {
            this.btnStartBackgroundWork.Enabled = true;
            this.btnCancelBackgroundWork.Enabled = false;
        }

        private void btnStartBackgroundWork_Click(object sender, EventArgs e) {
            //關閉 btnStartBackgroundWork 按鈕
            btnStartBackgroundWork.Enabled = false;

            //開啟 btnCancelBackgroundWork 按鈕
            btnCancelBackgroundWork.Enabled = true;

            //設定 ProgressBar 最大值
            toolStripProgressBar1.Maximum = _Limit;

            //建立 BW 物件
            _BW = new BackgroundWorker();

            //設定是否支援非同步作業取消
            _BW.WorkerSupportsCancellation = true;

            //繫結 DoWork 事件,當非同步作業啟動時,會呼叫該事件
            _BW.DoWork += new DoWorkEventHandler(_BW_DoWork);

            //啟動非同步作業,並將參數傳入
            //在 DoWork 函式中,參數會由 DoWorkEventArgs 帶出
            _BW.RunWorkerAsync(0);
        }

        //非同步作業
        void _BW_DoWork(object sender, DoWorkEventArgs e) {
            //設定 BW 物件可以更新表單資訊報告進度
            _BW.WorkerReportsProgress = true;

            //繫結 ProgressChanged 事件,當 WorkerReportsProgress 屬性設為 true ,
            //會觸發該事件,同時在這麼函式下,可以更新表單資訊
            _BW.ProgressChanged += new ProgressChangedEventHandler(_BW_ProgressChanged);

            //當背景作業已完成時、取消、例外發生時皆會觸發該事件
            _BW.RunWorkerCompleted += new RunWorkerCompletedEventHandler(_BW_RunWorkerCompleted);

            //呼叫自訂函式
            DoAdd((BackgroundWorker)sender, e);
        }

        //非同步作業已完成
        void _BW_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
            if (e.Cancelled) // 如果非同步作業已被取消...
            {
                UpdateProgressBar("非同步作業已被取消。");

            } else // 如果非同步作業順利完成....
            {
                UpdateProgressBar("非同步作業順利完成。");
            }
        }

        private void DoAdd(BackgroundWorker worker, DoWorkEventArgs e) {
            int iComplete = (int)e.Argument;
            while (iComplete < _Limit) {

                //判斷使用者是否已經取消背景作業
                if (worker.CancellationPending == true) {

                    //設定取消事件
                    e.Cancel = true;

                    //跳出迴圈
                    break;
                }

                //呼叫這個方法,會觸發 ProgressChanged 事件            
                worker.ReportProgress(iComplete);
                
                iComplete++;

                //這邊睡一下,給緩衝去給表單的 UI 重劃,
                //系統會另外開一條執行緒去觸發事件 (_BW_ProgressChanged)。
                System.Threading.Thread.Sleep(1);
            }

        }

        //在這麼事件裡,可以存取表單的資訊
        void _BW_ProgressChanged(object sender, ProgressChangedEventArgs e) {
            //若是已經取消背景作業,就不去更新表單資訊,
            //否則會引發 [引動過程的目標傳回例外狀況]。
            if (((BackgroundWorker)sender).CancellationPending == false) {
                UpdateProgressBar(e.ProgressPercentage);
                UpdateTxtBox(e.ProgressPercentage);
            }
        }


        private void btnCancelBackgroundWork_Click(object sender, EventArgs e) {
            //取消背景作業
            this.CancelBackgroundWork();
        }

        private void CancelBackgroundWork() {
            // 在嘗試取消非同步作業前,先判斷非同步作業是否仍在執行中。
            if (_BW.IsBusy) {
                UpdateProgressBar("非同步作業計算中...");

                // 呼叫 BackgroundWorker 物件的 CancelAsync 方法來要求取消非同步作業。
                _BW.CancelAsync();
            }
        }

        //更新狀態文字
        private void UpdateProgressBar(string text) {
            toolStripStatusLabel1.Text = text;
        }

        //更新 ProgressBar
        private void UpdateProgressBar(int value) {
            toolStripProgressBar1.Value = value;
        }

        //更新 TxtBox
        private void UpdateTxtBox(int value) {
            textBox1.Text = value.ToString();
        }

        //關閉表單發生時
        private void Form1_FormClosing(object sender, FormClosingEventArgs e) {
            //取消背景作業
            this.CancelBackgroundWork();              
        }  
        
    }



輸出結果



當背景作業發生時,會不斷更新畫面,同時還是可以編輯 textbox 。


Link

http://www.dotblogs.com.tw/yc421206/archive/2009/02/15/7174.aspx

BackgroundWorker 元件概觀

BackgroundWorker 類別

HOW TO:實作使用背景作業的表單

DoWorkEventArgs 類別

Managed 執行緒處理的最佳實施方針

程式碼 TestBackgroundWork.rar

三小俠  小弟獻醜,歡迎指教