2010年11月10日 星期三

WPF - Thread and Dispatcher

WPF 執行緒:
WPF應用程式中主要有兩個執行緒(Thread):Rendering ThreadUI Thread
  • Rendering Thread: 在背景中執行並協助UI Thread完成工作
  • UI Thread: 主要負責處理InputEvent與程式碼的部分
WPF中, 所有UI工作和事件都是在UI Thread上完成. 每個WPF程式至少有一個Dispatcher物件和一個UI Thread. 而大部分WPF物件的操作都是binding在UI Thread上,其他的Thread如果想要直接操作這些UI物件, 是不被允許的, 因為只有建立 DispatcherObject 的Thread才可以存取UI物件。例如, 要讓其他的Thread存取 LabelContent 屬性, 將會發生錯誤, 此範例如下所示:
設計一個WPF視窗, 當按下Button後, 讓Label顯示按Button的次數.

C#程式碼如下所示:
private static int _clickCount = 0;
private void btnShowText_Click(object sender, RoutedEventArgs e)
{
      _clickCount++;
       // Update Label Conten in another thread
       Thread updateThread = new Thread(UpdateText);
       updateThread.Start();
 }
 private void UpdateText()
 {
      labelClickCount.Content = "Click Count= " + _clickCount.ToString();
 }

[圖1]無法再另一個Thread中更新UI


Dispatcher用法:

Dispatcher可讓其他的ThreadWPF中的 UI Thread上執行程式碼. Dispatcher又被稱為WPF中的Message Pump,提供一個機制去發送工作項目給UI Thread進行處理.  
Dispatcher將工作項目轉給UI Thread時, 會讓UI Thread進入封鎖狀態(畫面鎖定, 因為要處理工作項目). 其他的Thread必須將工作委派給與 UI Thread相關聯的 Dispatcher. 這可以使用 Invoke BeginInvoke 完成.
  • Invoke 是同步呼叫,也就是說,除非 UI 執行緒實際完成委派的執行,否則不會返回. 
Dispatcher 會依優先權排列其佇列中項目的順序. 在將項目加入至 Dispatcher 佇列.

下面的程式碼, 將說明其解決方法:
C#程式碼如下所示:

private static int _clickCount = 0;

 // Declare a delegate type for updating UI
 private delegate void UpdateDelegate(int number, string str);
 private void btnShowText_Click(object sender, RoutedEventArgs e)
 {
     _clickCount++;
     Thread updateThread = new Thread(UpdateText);
      updateThread.Start();
 }

 private void UpdateText()
 {
      //labelClickCount.Content = "Click Count= " + _clickCount.ToString();
      // Places the delegate onto the UI Thread's Dispatcher
      Dispatcher.Invoke(new UpdateDelegate(UpdateClickCountAction),
                                          _clickCount, 
                                          "Click Count = ");
 }

  private void UpdateClickCountAction(int number, string str)
  {
       labelClickCount.Content = str + number.ToString();
  }

[圖2] 利用Dispatcher執行另一個Thread的function

參考文章:

沒有留言:

張貼留言