前言
C# Winform作為視窗程式設計的入門,提供容易上手的開發工具及各種好用的UI控制元件,可以輕鬆開發出簡單的小程式。
在開發過程中,常會用執行緒(thread)去執行耗時的工作,例如讀寫檔案,或是做大量的運算,來避免表單(form)的執行緒被占住,導致視窗卡頓甚至反白轉圈圈。

當我們將計算好的結果顯示到畫面上時,卻發生了“跨執行緒存取無效: 存取控制項 ‘textBox1’ ” 時所使用的執行緒與建立控制項的執行緒不同。”的錯誤,這時程式就崩潰消失了。
這是什麼原因?
跨執行緒錯誤的原因
下圖使用Task開一個執行緒去更新表單元件,馬上引發錯誤。

當發生“跨執行緒存取無效“的狀況,是因為在非表單執行緒去更新表單元件。一個視窗會有自己用來更新畫面的執行緒,當有非表單執行緒去更新資料時就會發生錯誤。
判斷是否跨執行緒
如何判斷執行當下是否為表單執行緒的動作很簡單,只需要看Control.InvokeRequired屬性,true
的話表示需要調用(invoke)表單的執行緒,false
則是目前是以表單執行緒在執行。
在官方文件中有提到”取得一個值。這個值會指示是否由於呼叫端是在建立控制項之執行緒以外的執行緒,因此在進行控制項的方法呼叫時,應呼叫調用方法。“
if (InvokeRequired)
{
//非UI執行緒
}
else
{
//UI執行緒
}
匿名委派(Lambda)方法
當需要更新控制元件的數值時,需要呼叫委派(delegate)來調用表單的執行緒,將更新的動作交由表單執行緒來完成。
想了解委派的運作可以參考這篇。
public void UpdateUI(string text)
{
if (InvokeRequired)
{
Invoke((Action)(() => UpdateUI(text)));
}
else
{
textBox1.Text = text;
}
}
當使用委派去調用表單執行緒就不會發生錯誤了!

這方法在實務上很常用而且非常簡單,使用匿名委派去調用相同的方法,完全不需要另外寫委派,熟練地使用lambda可以大量的簡化程式碼的篇幅。
發佈留言