Windows Forms 控件具有線程親和性,只能在創建它們的線程(UI 線程)上訪問。子線程直接操作控件會拋出 InvalidOperationException。
Control.Invoke 同步委托到 UI 線程執行;BeginInvoke 異步委托,不阻塞調用線程。
using System;
using System.Threading;
using System.Windows.Forms;
public partial class MainForm : Form
{
private ProgressBar prgBar;
private Thread workThread;
public MainForm()
{
prgBar = new ProgressBar { Dock = DockStyle.Top, Maximum = 100 };
Controls.Add(prgBar);
Button btn = new Button { Text = "開始", Dock = DockStyle.Bottom };
btn.Click += (s, e) => StartWork();
Controls.Add(btn);
}
private void StartWork()
{
workThread = new Thread(ThreadFun);
workThread.Start();
}
// UI 線程執行的委托方法
private void UpdateProgress()
{
if (prgBar.Value < 100) prgBar.Value++;
}
// 工作線程入口
private void ThreadFun()
{
MethodInvoker mi = new MethodInvoker(UpdateProgress);
for (int i = 0; i < 100; i++)
{
BeginInvoke(mi); // 異步提交,不阻塞工作線程
Thread.Sleep(100);
}
}
}
Invoke/BeginInvoke 優化BeginInvoke 任務排入 UI 消息隊列自動執行
private void SetText(string text)
{
if (txtBox.InvokeRequired)
txtBox.BeginInvoke(new Action(SetText), text);
else
txtBox.Text = text;
}
// 工作線程中調用
SetText("來自線程的消息");
InvokeRequired 屬性檢查當前線程是否為 UI 線程,實現同一方法雙模式調用。
跨線程操作 UI 的核心原則:將操作封裝為委托,通過 Invoke/BeginInvoke 交給 UI 線程執行。優先使用 BeginInvoke 避免死鎖風險,配合 InvokeRequired 編寫線程安全的通用方法。