測試軟件運行測試邏輯時,UI 完全無響應(「假死」),直到測試結束界面才恢復。
**耗時操作佔用了 UI 線程(主線程)**。WinForm 單線程模型:UI 繪製、事件處理、用戶交互全在主線程。同步執行長任務會阻塞消息泵,導致界面無法重繪、無法響應點擊。
private async void btnStartTest_Click(object sender, EventArgs e) {
btnStartTest.Enabled = false;
try {
// 耗時操作放入線程池
await Task.Run(() => {
RunLongTest(); // 這裡不能直接操作 UI 控件
});
MessageBox.Show("測試完成");
} catch (Exception ex) {
MessageBox.Show("錯誤: " + ex.Message);
} finally {
btnStartTest.Enabled = true;
}
}
private void btnStartTest_Click(object sender, EventArgs e) {
ThreadPool.QueueUserWorkItem(_ => {
RunLongTest();
// 跨線程更新 UI 必須用 Invoke
this.Invoke((Action)(() => {
MessageBox.Show("測試完成");
btnStartTest.Enabled = true;
}));
});
}
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += (s, e) => { RunLongTest(); };
bw.RunWorkerCompleted += (s, e) => {
MessageBox.Show("完成");
btnStartTest.Enabled = true;
};
bw.RunWorkerAsync();
Control.Invoke / BeginInvoke 或 Progress<T> 回調到 UI 線程。.Result、.Wait()),會導致死鎖或假死。try/catch 中捕獲,否則靜默失敗。var progress = new Progress<int>(p => progressBar.Value = p);
var cts = new CancellationTokenSource();
await Task.Run(() => {
for (int i = 0; i < 100; i++) {
cts.Token.ThrowIfCancellationRequested();
Thread.Sleep(50); // 模擬工作
progress.Report(i + 1); // 自動切回 UI 線程
}
}, cts.Token);
**長耗時任務必須移出 UI 線程**。現代 C# 首選 async/await + Task.Run,配合 IProgress<T> 更新進度,**嚴禁在後台線程直接操作控件**,用 Invoke 回調。這樣界面永遠流暢響應。