首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

BackgroundWorker 元件實作非同步程式設計完整指南

     編輯:關於.NET

.NET 2.0+ 提供 System.ComponentModel.BackgroundWorker,以事件基礎非同步模式 (EAP) 簡化多執行緒程式設計,自動處理跨執行緒 UI 更新、進度回報、取消作業等常見需求。

核心成員速查

成員用途
RunWorkerAsync()啟動非同步作業,觸發 DoWork 事件。
CancelAsync()請求取消,設定 CancellationPending = true。
ReportProgress(int, object)回報進度,觸發 ProgressChanged 事件 (需 WorkerReportsProgress=true)。
WorkerSupportsCancellation允許取消作業。
WorkerReportsProgress允許進度回報。
IsBusy檢查是否正在執行。
DoWork背景執行緒執行實際工作,不可存取 UI。
ProgressChangedUI 執行緒,安全更新進度條/狀態。
RunWorkerCompletedUI 執行緒,處理完成/取消/例外結果。

完整範例:1 到 N 求和與進度顯示

1. 初始化與事件註冊

private BackgroundWorker backgroundWorker1;

private void InitializeBackgroundWorker()
{
    backgroundWorker1 = new BackgroundWorker();
    backgroundWorker1.WorkerReportsProgress = true;
    backgroundWorker1.WorkerSupportsCancellation = true;
    backgroundWorker1.DoWork += BackgroundWorker1_DoWork;
    backgroundWorker1.ProgressChanged += BackgroundWorker1_ProgressChanged;
    backgroundWorker1.RunWorkerCompleted += BackgroundWorker1_RunWorkerCompleted;
}

2. 啟動作業

private void StartAsyncButton_Click(object sender, EventArgs e)
{
    resultLabel.Text = "";
    numericUpDown1.Enabled = false;
    startAsyncButton.Enabled = false;
    cancelAsyncButton.Enabled = true;

    int n = (int)numericUpDown1.Value;
    backgroundWorker1.RunWorkerAsync(n); // 傳入參數
}

3. 背景工作邏輯 (DoWork)

private void BackgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    BackgroundWorker worker = sender as BackgroundWorker;
    e.Result = ComputeSum((int)e.Argument, worker, e);
}

private long ComputeSum(int n, BackgroundWorker worker, DoWorkEventArgs e)
{
    long sum = 0;
    for (int i = 1; i <= n; i++)
    {
        if (worker.CancellationPending)
        {
            e.Cancel = true;
            break;
        }
        sum += i;
        Thread.Sleep(500); // 模擬耗時運算
        int percent = (int)((float)i / n * 100);
        worker.ReportProgress(percent);
    }
    return sum;
}

4. 進度更新 (ProgressChanged)

private void BackgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    progressBar1.Value = e.ProgressPercentage;
}

5. 完成處理 (RunWorkerCompleted)

private void BackgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    if (e.Error != null)
        MessageBox.Show(e.Error.Message);
    else if (e.Cancelled)
        resultLabel.Text = "已取消";
    else
        resultLabel.Text = e.Result.ToString();

    numericUpDown1.Enabled = true;
    startAsyncButton.Enabled = true;
    cancelAsyncButton.Enabled = false;
}

進階:獨立進度對話框 (Modal/ Modeless)

  • 建立 ProcessForm 接收 BackgroundWorker 參考,註冊其 ProgressChanged、RunWorkerCompleted 事件更新自身 UI。
  • 啟動時 form.ShowDialog(this) (模態) 或 form.Show(this) (非模態)。
主視窗介面 進度對話框

內部實作原理解析

  • RunWorkerAsync 內部透過 AsyncOperationManager.CreateOperation 建立 AsyncOperation,並以委派 BeginInvoke 執行 WorkerThreadStart。
  • WorkerThreadStart 引發 DoWork,完成後透過 asyncOperation.PostOperationCompleted 將 RunWorkerCompletedEventArgs 送回 UI 執行緒。
  • ReportProgress 透過 asyncOperation.Post 送回 UI 執行緒引發 ProgressChanged。
  • 已知問題: 若 asyncOperation 為 null,ReportProgress 會直接呼叫 progressReporter 導致跨執行緒 UI 存取例外 (WinForms),主控台應用程式不受影響。

結語

BackgroundWorker 封裝了非同步委派、同步上下文切換、取消協調等複雜細節,是 WinForms/WPF 應用程式執行長時間作業的首選元件。理解其事件流程與內部機制,有助於擴充支援多工作業佇列、錯誤重試等進階需求。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved