.NET 2.0+ 提供 System.ComponentModel.BackgroundWorker,以事件基礎非同步模式 (EAP) 簡化多執行緒程式設計,自動處理跨執行緒 UI 更新、進度回報、取消作業等常見需求。
| 成員 | 用途 |
|---|---|
RunWorkerAsync() | 啟動非同步作業,觸發 DoWork 事件。 |
CancelAsync() | 請求取消,設定 CancellationPending = true。 |
ReportProgress(int, object) | 回報進度,觸發 ProgressChanged 事件 (需 WorkerReportsProgress=true)。 |
WorkerSupportsCancellation | 允許取消作業。 |
WorkerReportsProgress | 允許進度回報。 |
IsBusy | 檢查是否正在執行。 |
DoWork | 背景執行緒執行實際工作,不可存取 UI。 |
ProgressChanged | UI 執行緒,安全更新進度條/狀態。 |
RunWorkerCompleted | UI 執行緒,處理完成/取消/例外結果。 |
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;
}
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); // 傳入參數
}
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;
}
private void BackgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
}
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;
}
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 應用程式執行長時間作業的首選元件。理解其事件流程與內部機制,有助於擴充支援多工作業佇列、錯誤重試等進階需求。