C# Development | 煩人的跨執行緒作業無效 : 如何跨執行緒控制 UI 元件
撰寫多執行緒的程式時,常會需從 UI 介面取得或顯示資料,但是要取得或顯示資料常會發生跨執行緒存取權限的問題。
前言
因為最近在寫控制類的 DLL ,但為了要測試 DLL 裡面的功能,所以也要寫一個簡單的測試 UI,而寫 UI 通常以主執行緒來控制介面與介面元件避免畫面凍結卡死,然後將需要運算時間較長的函式丟到其他執行緒來執行,並在最後顯示結果即可。但要從 UI 介面上取得輸入資料或是將運算完畢的資料顯示時就常會發生跨執行緒存取權限的問題。
簡介
那要如何判斷是否為跨執行緒來執行函式?在 Control 類別( Class )內其中有一個屬性 ( Properties ) : InvokeRequired,在 MSDN 內描述為「取得一個值。這個值會指示是否由於呼叫端是在建立控制項之執行緒以外的執行緒,因此在進行控制項的方法呼叫時,應呼叫叫用 (Invoke) 方法。」
簡單來說,若 InvokeRequired 為 True 則代表為跨執行緒執行,應用 Invoke 方式呼叫執行函式;或InvokeRequired 為 False 則代表非跨執行緒執行,直接執行函式即可。
若想直接看解法可下拉至 Get Start — 解決跨執行緒作業無效的問題。
- InvokeRequired 屬性 MSDN 連結 :
Get Start - 撰寫跨執行緒顯示的程式
1. 先建立一個簡單的小專案 ( 本文是用 Visual Studio 2015, .NET Framework 4.5.2, 專案類型為 Windows Form Application )。
2. 新增一個 Button ( button1 ) 元件及 TextBox ( textBox1 )元件,Button 功能為當按下時開始另外的執行緒,並定時顯示文字於 TextBox 中。
3. 附上 source code,當按下執行時會出現 " 跨執行緒作業無效 " 的錯誤,代表執行此函式的執行緒與控制 textBox1 的執行緒不同。
Get Start — 解決跨執行緒作業無效的問題
解決方法就是利用委派 ( delegate ) 的方式將要處理的函式交給可以控制 UI 元件的執行緒來執行。
- 先宣告一個委派 ( 是否要輸入值看個人需求 )。
private delegate void DelShowMessage(string sMessage);
2. 接著將修改 " AddMessage " 函式,若非與 UI 元件控制權同執行緒則用 Invoke 方式委派執行;若為同執行緒則直接執行。
3. 附上完整程式碼
執行結果
執行後按下 button1 在 textBox1 內每過3秒就會顯示 " Thread is alive… " 的文字,可以成功的控制 UI 元件。
尾聲
跨執行緒作業無效是開發 UI 介面時常發生的錯誤,不過解法也不是很困難,既然常遇到就在這邊分享紀錄一下。
最近看到這個影片覺得很值得分享,有時候其實大家不太認同你的價值觀或是所作所為,覺得你的努力似乎是在白費力氣。但你的自信與成就感應該建立在你的自我實現上,即使機會再小,你曾經為了這個目標盡了多少努力其實你自己最清楚,就算結果是失敗的,你也可以很自豪地說 " 至少我曾經全力以赴過了 "。與其活在後悔當初沒嘗試的悔恨中,倒不如坦然接受全力以赴之後的結果。