在開發 Winform 時,碰到這種例外狀況:跨執行緒作業無效
,原因是:當對 UI 控制項 更動的執行緒
與 UI 控制項的執行緒
不相同,這會導致對 UI 控制項進行不安全的調用,從而引發此例外錯誤。
示例
簡單寫了個介面,功能為:點擊計數
按鈕時,灰色區域要顯示 0 ~ 9 的數字(如右)
計數按鈕程式碼:
/// <summary>
/// 計數
/// </summary>
private void BtnCount_Click(object sender, EventArgs e)
{
for (int i = 0; i < 10; i++)
{
LblView.Text += $"{i} \r\n";
}
}
若改為由不同的執行緒處理時:
/// <summary>
/// 計數
/// </summary>
private void BtnCount_Click(object sender, EventArgs e)
{
Thread thread = new Thread(() =>
{
for (int i = 0; i < 10; i++)
{
LblView.Text += $"{i} \r\n";
}
});
thread.Start();
}
點擊時,則會引發錯誤
解決方式
首先建立宣告委派 DelSetLalView
及要委託執行的方法(這邊指設定 LblView.Text
的這個行為,後續會在宣告 SetLblView
方法),如下:
/// <summary>
/// 委派 SetLalView
/// </summary>
public delegate void DelSetLblView(int num);
// ...
private void SetLblView(int num)
{
LblView.Text += $"{num} \r\n";
}
之後宣告 SetLblViewSafely
方法,並且這方法會判斷是否需進行安全調用,如下:
private void SetLblViewSafely(int num)
{
// 若為不同執行緒,則 InvokeRequired 會為 ture,表示需進行安全的調用
if (this.InvokeRequired)
{
DelSetLblView del = new DelSetLblView(SetLblView);
this.Invoke(del, new object[] { num });
}
else
{
SetLblView(num);
}
}
完整程式碼:
/// <summary>
/// 委派 SetLalView
/// </summary>
public delegate void DelSetLblView(int num);
public Form1()
{
InitializeComponent();
}
/// <summary>
/// 計數
/// </summary>
private void BtnCount_Click(object sender, EventArgs e)
{
Thread thread = new Thread(() =>
{
for (int i = 0; i < 10; i++)
{
SetLblViewSafely(i);
}
});
thread.Start();
}
private void SetLblViewSafely(int num)
{
// 若為不同執行緒,則 InvokeRequired 為 ture,表示需進行安全的調用
if (this.InvokeRequired)
{
DelSetLblView del = new DelSetLblView(SetLblView);
this.Invoke(del, new object[] { num });
}
else
{
SetLblView(num);
}
}
private void SetLblView(int num)
{
LblView.Text += $"{num} \r\n";
}
如此一來,即可在不同執行緒的情況下,安全改動 UI 控制項囉!
若懶得寫得像上述那麼繁瑣,改成這樣就好:
private void SetLblViewSafely(int num)
{
Action action = () => LblView.Text += $"{i} \r\n";
// 若為不同執行緒,則 InvokeRequired 為 ture,表示需進行安全的調用
if (this.InvokeRequired)
{
this.Invoke(action);
}
else
{
action.Invoke();
}
}
參考
C# Development | 煩人的跨執行緒作業無效 : 如何跨執行緒控制 UI 元件
如何 Windows Forms .net) 對控制項進行安全線程呼叫