VS 2005 引入的 BackgroundWorker 大幅簡化 WinForms 多線程開發,但其事件流與參數傳遞機制若不清晰,極易踩坑。本文梳理完整生命週期、三次關鍵參數傳遞、UI 線程邊界規則。
| 類別 | 成員 | 作用 |
|---|---|---|
| 屬性 | CancellationPending | 是否請求取消 |
| IsBusy | 是否正在運行 | |
| WorkerReportsProgress | 啟用進度報告 | |
| WorkerSupportsCancellation | 啟用異步取消 | |
| 方法 | RunWorkerAsync(obj) | 啟動後台操作,傳參 |
| CancelAsync() | 請求取消 | |
| ReportProgress(%) | 觸發 ProgressChanged | |
| 事件 | DoWork | 後台線程執行核心邏輯 |
| ProgressChanged | UI 線程更新進度 | |
| RunWorkerCompleted | UI 線程處理完成/取消/異常 |
RunWorkerAsync(obj) → DoWorkEventArgs.Argument。建議封裝為上下文類實例。ReportProgress(%, userState) → ProgressChangedEventArgs.ProgressPercentage / UserState。用於更新進度條、日誌。DoWorkEventArgs.Result = result → RunWorkerCompletedEventArgs.Result。攜帶後台計算結果回 UI 線程。private void btnStart_Click(object sender, EventArgs e)
{
if (bw.IsBusy) return;
bw.RunWorkerAsync(new WorkContext { Input = txtInput.Text });
}
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
var ctx = (WorkContext)e.Argument;
for (int i = 0; i < 100; i++)
{
if (bw.CancellationPending) { e.Cancel = true; return; }
// 耗時計算...
bw.ReportProgress(i, $"Step {i} done");
}
e.Result = ctx.Output; // 設置結果
}
private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
pgb.Value = e.ProgressPercentage;
lstLog.Items.Add(e.UserState);
}
private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled) MessageBox.Show("已取消");
else if (e.Error != null) MessageBox.Show("錯誤: " + e.Error.Message);
else txtResult.Text = e.Result.ToString();
}
WorkerSupportsCancellation = true 後,DoWork 中必須輪詢 CancellationPending 並設置 e.Cancel = true。RunWorkerCompleted 中檢查 e.Error,DoWork 中未捕獲的異常會自動封送至此。IsBusy 防止重複啟動。