2010年12月26日 星期日

GUI Thread on C#

在C#中,一般情況下,控制GUI元件時,必須要用main thread去控制。然而我們常常將運算丟至一個新的thread中,然後在運算時更新GUI的狀態。這時例外就會警告你不能這樣做。MSDN提供了delegate解法去做,但我覺得麻煩,也不夠直覺。後來參考了這裡,是使用SynchronizationContext,發現還挺好用的。使用方如下。

首先在GUI class範疇下宣告SynchronizationContext。

public partial class A:Form{
    SynchronizationContext mainSynchronizationContext;
}

接著在constructor上面,將SynchronizationContext做指定。這樣SynchronizationContext就可以抓得到現在的執行緒。

public partial class A:Form{
    public A(){
        mainSynchronizationContext = SynchronizationContext.Current;
    }
}

然後寫一個方法,負責執行GUI更新動作。label1在這裡是一個Lebel類別

public void InvokeGUI(string str) {
    mainSynchronizationContext.Post
        (
        new SendOrPostCallback
            (
            (obj)
            =>
            {
               label1.Text=(String)obj;
               
            }
            )
            ,
            str
       );
}

其中mainSynchronizationContext.Post,是非同步處理,指的是不會等待GUI就進行下一步驟。如果使用mainSynchronizationContext.Send的話,則是進行同步處理。當GUI真正動作完成才會做返回動作。script則是傳入的引數。

然後在你的thread運算時呼叫這個function,便不會拋出例外訊息了。

參考資料:
[1] (筆記) 跨執行緒存取控制項 (WPF、WinForm 通用)
[2] 深入线程,实现自定义的SynchronizationContext

第[2]有詳細說明SynchronizationContext的原理,推薦可以看看。

沒有留言: