.NET 2.0+ 預設啟用跨執行緒檢查。非 UI 執行緒直接存取控制項屬性 (如 textBox.Text = "...") 會拋出 InvalidOperationException:「跨執行緒操作無效: 存取控制項 'xxx' 不是在建立它的執行緒上。」
private void Form_Load(object sender, EventArgs e) {
Control.CheckForIllegalCrossThreadCalls = false; // 全域關閉檢查
}
private void UpdateUI(string msg) {
if (this.textBox1.InvokeRequired) {
this.Invoke(new Action(UpdateUI), msg); // 切換到 UI 執行緒
return;
}
textBox1.AppendText(msg + Environment.NewLine); // 安全存取
}
private void UpdateUIAsync(string msg) {
if (this.textBox1.InvokeRequired) {
this.BeginInvoke(new Action(UpdateUIAsync), msg);
return;
}
textBox1.AppendText(msg);
}
this.Invoke((MethodInvoker)delegate {
textBox1.Text = "Updated from thread " + Thread.CurrentThread.ManagedThreadId;
});
// 或
this.BeginInvoke((Action)(() => {
progressBar1.Value = percent;
}));
// WinForms 同步上下文捕獲
private readonly SynchronizationContext _uiContext = SynchronizationContext.Current;
public void LogFromWorker(string msg) {
_uiContext.Post(_ => txtLog.AppendText(msg + "\n"), null); // 自動切換到 UI 執行緒
}
// .NET 4.5+ Task + await (需在 UI 執行緒呼叫)
private async void btnStart_Click(object sender, EventArgs e) {
await Task.Run(() => {
// 背景運算
var result = ComputeHeavy();
// 回到 UI 執行緒 (捕獲上下文)
txtResult.Text = result;
});
}
Invoke 將委派封裝為訊息發送到 UI 執行緒訊息隊列,UI 執行緒取出執行,呼叫端等待完成。BeginInvoke 非同步投遞,不等待。SynchronizationContext 抽象化了「排程到特定執行緒」操作,支援 WinForms/WPF/ASP.NET 統一模型。Invoke 等待背景執行緒,背景執行緒又 Invoke 等待 UI → 互相等待。解:用 BeginInvoke 或 async/await。Invoke 時視窗已關閉 → ObjectDisposedException。解:if (!IsDisposed && !Disposing) Invoke(...)。Invoke 更新。CheckForIllegalCrossThreadCalls = false 是技術債,而非解決方案。請掌握 Invoke/BeginInvoke、SynchronizationContext、async/await 三種正規模式,根據同步/非同步需求、.NET 版本選擇,確保 UI 執行緒安全、響應流暢、邏輯正確。