C# 使用 BackgroundWorker 背景執行

BackgroundWorker

要寫背景執行程式,可以自己寫多執行緒來處理。如果需求不複雜,在 C# 中可以使用 BackgroundWorker 來處理。會用到背景執行,是為了讓程式在執行長時間的運算時,不要讓使用者界面看起來像是當機一樣停止不動。

使用方法

  • RunWorkerAsync()方法:啟動背景執行時呼叫。
  • CancelAsync()方法:取消背景執行。
  • ReportProgress()方法:在DoWork事件處理函式中,送出進度報告,會被ProgressChanged事件接收。
  • DoWork事件:要在背景作業的程式放在DoWork事件的處理函式裡。需注意的是,在DoWork事件的處理函式裡不能有任何和UI元件的互動。
  • ProgressChanged事件:處理進度的顯示。可以和UI元件互動。
  • RunWorkerCompleted事件:執行完成。可以和UI元件互動。
  • WorkerReportsProgress屬性:設定是否可以接收進度報告。
  • WorkerSupportsCancellation屬性:設定是否支援非同步取消。
  • CancellationPending屬性:在DoWork事件處理函式裡,用來判斷是否有要求取消背景執行。
  • IsBusy屬性:在啟動背景作業之前,用來檢查是否仍有在執行的背景作業。
建立BackgroundWorker物件後,加入事件DoWork、ProgressChanged、RunWorkerCompleted,若要允許傳送處理進度,則WorkerReportsProgress屬性要設為true,若要允許背景執行程式可以中途被中斷,則WorkerSupportsCancellation要設為true。

當你要啟動背景執行時,例如按下按鈕就啟動背景執行作業,那就是在按鈕裡呼叫RunWorkerAsync()來啟動,你的BackgroundWorker物件的DoWork事件會收到事件觸發而執行DoWork事件處理函式中的程式。

在DoWork事件處理函式中的程式會一直執行直到結束,在執行期間可以呼叫ReportProgress()方法來送出處理進度,ProgressChanged事件會收到觸發而執行該處理函式裡的程式,例如改變ProgressBar的進度值。

當DoWork事件處理函式中的程式執行完畢,就會觸發RunWorkerCompleted事件。你也可以在DoWork事件中加入CancellationPending屬性的判斷,當使用者按下取消(也就是呼叫CancelAsync()方法)時,CancellationPending屬性會被設為false,你就可以強制DoWork處理函式中的程式結束。

另外,當你要啟動背景執行之前,可以用IsBusy屬性來判斷,該背景執行程式是否仍在執行中。

範例程式碼

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace BackgroundWorkerDemo
{
  public partial class Form1 : Form
  {
     private BackgroundWorker bw;

    public Form1()
    {
      InitializeComponent();

      initProgressBar();
      initBackgroundWorker();
    }

    private void initProgressBar()
    {
      progressBar1.Step = 1;
    }

    private void initBackgroundWorker()
    {
      bw = new BackgroundWorker();
      bw.WorkerReportsProgress = true;
      bw.WorkerSupportsCancellation = true;
      bw.DoWork += new DoWorkEventHandler(bw_DoWork);
      bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
      bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
    }

    //背景執行
    private void bw_DoWork(object sender, DoWorkEventArgs e)
    {
      for (int i = 1; (i <= 10); i++)
      {
        if ((bw.CancellationPending == true))
        {
          e.Cancel = true;
          break;
        }
        else
        {
          // 使用sleep模擬運算時的停頓
          System.Threading.Thread.Sleep(500);
          bw.ReportProgress((i * 10));>
        }
      }
    }

    //處理進度
    private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
      progressBar1.Value = e.ProgressPercentage;
      this.lblMsg.Text = e.ProgressPercentage.ToString();
    }

    //執行完成
    private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {

      if ((e.Cancelled == true))
      {
        this.lblMsg.Text = "取消!";
      }
      else if (!(e.Error == null))
      {
        this.lblMsg.Text = ("Error: " + e.Error.Message);
      }
      else
      {
        this.lblMsg.Text = "完成!";
      }
    }

    private void btnStart_Click(object sender, EventArgs e)
    {
      if (bw.IsBusy != true)
      {
        this.lblMsg.Text = "開始";
        this.progressBar1.Value = 0;
        bw.RunWorkerAsync();
      }
    }

    private void btnFinish_Click(object sender, EventArgs e)
    {
      if (bw.WorkerSupportsCancellation == true)
      {
        bw.CancelAsync();
      }
    } 

  }
}

參考資源

本文網址:https://blog.tonycube.com/2011/04/backgroundworker.html
Tony Blog 撰寫,請勿全文複製,轉載時請註明出處及連結,謝謝 😀

1 則留言

留言小提醒:
1.回覆時間通常在晚上,如果太忙可能要等幾天。
2.請先瀏覽一下其他人的留言,也許有人問過同樣的問題。
3.程式碼請先將它編碼後再貼上。(線上編碼:http://bit.ly/1DL6yog)
4.文字請加上標點符號及斷行,難以閱讀者恕難回覆。
5.感謝您的留言,您的問題也可能幫助到其他有相同問題的人。