WinForms UI thread HowTo

最近亂玩.NET的SOCKET PROGRAMMING時無意中遇上這個問題,於是在網路上看了一堆文章找答案,但我發現好像沒甚麼中文的資料,英文的倒是有很詳細的解說,所以我這裡會用中文說明,英文的可以看這一遍,很詳細,我也沒有看完細節,有人說菜鳥寫AP跟中鳥寫AP的分界就在這裡.

我會用我的理解簡單說明怎麼用,不會解釋原理.先說明我們在解的是甚麼問題,如果你的WinForms Application只有Single Thread,當你的Thread進到一個長的Looping時,你的UI就會被凍住,變成一遍空白,因為你在跑Loop的Thread,就是UI Thread,所以UI沒有辦法更新,就變空白了.

那該怎麼辦呢,就是用Multi Thread,這個在.NET不難,但另一個問題來了,當你的worker thread計算完,想更新UI去顯示結果,那怎麼辦呢?例如你有一個TextBox tb_result,你在worker thread調用tb_result.Text = someResult,你就會收到一個crossthread Exception,因為你的worker thread不是產生TextBox的thread,.NET不會讓你這樣更改它的property.

這時候我們就要借delegate去解決這個問題,我們有兩個選擇,synchronous和asynchronous,分別用control.Invoke()和control.BeginInvoke()去達成

Example :
Method without parameter

private void BunchOfCode() {
myControl.Focus();
myControl.SomethingElse();
}
myControl.Invoke(new MethodInvoker(this.BunchOfCode());

Method works with any control

private void BunchOfCode(object sender, EventArgs e) {
Control c = sender as Control;
if ( c != null ) {
c.Focus();
c.SomethingElse();
}
}
myControl.Invoke(new EventHandler(BunchOfCode));

那如果要傳參數呢?

delegate void UpdateDelegate(string value);
public void UpdateLabel(string value)
        {
            if (this.m_tbReceieve.InvokeRequired)
            {
                //worker thread
                this.m_tbReceieve.Invoke(new UpdateDelegate(UpdateLabel), new object[] { value });
            }
            else
            {
                //gui thread
                this.m_tbReceieve.Text = value;
                //receieveMsg();
            }
        }
UpdateLabel(result);

接下來解釋,首先我們用control.InvokeRequired來判斷是那個Thread在跑,這其實是一個method,拿現在的Thread跟UI Thread去比較,如果是同一個Thread就會return true,裡面其實還有很多細節,但我就跳過了.這裡的做法是UI Thread就直接改Property,如果是Worker Thread就新增一個delegate丟給那個control.可以理解成它有個queue,等到UI Thread在跑時就會去處理queue裡的delegate.

Asynchronous的用法也大同小異,用BeginInvoke代替Invoke就應該可以.這樣做之後UI就不會再被凍住了

Advertisements

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s