子線程直接操作 UI 控件 (textBox.AppendText) 不生效或異常,加 Thread.Sleep() 後「好像」正常 → **實為睡眠讓出時間片,主線程偶爾處理消息泵刷新界面,非根治**。
// 1. 同步 Invoke (阻塞子線程直到 UI 執行完)
this.Invoke((Action)(() => {
textBox.AppendText("日誌內容" + Environment.NewLine);
}));
// 2. 異步 BeginInvoke (不阻塞子線程,推薦高頻日誌)
this.BeginInvoke((Action)(() => {
textBox.AppendText("日誌內容" + Environment.NewLine);
}));
// 3. 檢查 InvokeRequired (通用封裝)
public void SafeAppend(string msg) {
if (textBox.InvokeRequired) {
textBox.BeginInvoke((Action)(() => SafeAppend(msg)));
} else {
textBox.AppendText(msg + Environment.NewLine);
}
}
// Dispatcher 優先級可控
Application.Current.Dispatcher.InvokeAsync(() => {
textBox.AppendText("日誌內容" + Environment.NewLine);
}, DispatcherPriority.Background);
Thread.Sleep(1) 釋放 CPU 時間片,主線程獲取調度權處理消息隊列中的 WM_PAINT 等繪製消息,**僅是巧合時序**,高負載下依然會丟失更新或死鎖。
// 子線程緩衝區
ConcurrentQueue logQueue = new ConcurrentQueue();
// 子線程生產
logQueue.Enqueue("大量日誌...");
// UI 線程定時消費 (Timer 100ms)
private void timer_Tick(object sender, EventArgs e) {
while (logQueue.TryDequeue(out var msg)) {
textBox.AppendText(msg + Environment.NewLine);
}
// 限制行數防止內存漲
if (textBox.Lines.Length > 5000) {
textBox.Text = string.Join(Environment.NewLine, textBox.Lines.Skip(1000));
}
}
Thread.Sleep() 不是解決方案,是掩盖問題的止痛藥。 掌握 Invoke/BeginInvoke (WinForms) 或 Dispatcher.InvokeAsync (WPF),構建線程安全、高性能的 UI 更新機制。