演算法在 **UI 執行緒** 中同步運行,佔用訊息泵,導致界面無法重繪,直到演算結束才一次性顯示最終結果。
private void SolveKnightTour() {
for (int step = 1; step <= 64; step++) {
// ... 計算下一步位置 ...
pictureBox.Image = GenerateBoardBitmap(); // 更新圖片
Application.DoEvents(); // 關鍵:處理待處理的 Windows 訊息 (含 WM_PAINT)
Thread.Sleep(50); // 可選:控制動畫速度
}
}
Application.DoEvents() 讓當前執行緒**暫時離開**演算法代碼,**進入訊息迴圈**處理繪製、輸入等訊息,完成後返回繼續演算法。相當於人工插入「讓出 CPU」點。
private async void btnStart_Click(object sender, EventArgs e) {
btnStart.Enabled = false;
var progress = new Progress(step => {
pictureBox.Image = GenerateBoardBitmap(step);
});
await Task.Run(() => KnightTourSolver.Solve(progress));
btnStart.Enabled = true;
}
// 解算器
public static void Solve(IProgress progress) {
for (int step = 1; step <= 64; step++) {
// ... 計算 ...
progress.Report(step); // 自動切換到 UI 執行緒調用
Thread.Sleep(50);
}
}
| 方案 | 優點 | 缺點 |
|---|---|---|
| DoEvents | 代碼改動極小、易理解 | 重入風險、阻塞 UI 執行緒、不推薦新專案 |
| async/await + Task | 非阻塞、符合現代模式、支援取消/異常處理 | 需理解異步編程、代碼結構調整大 |
| BackgroundWorker | .NET 2.0 經典、支援進度報告 | 已過時、不支援 async/await |
**教學/快速驗證用 DoEvents**;**正式專案請用 async/await + Task**,避免 UI 凍結、重入 Bug。