WPF Dispatcher在界面操作中作用体现

WPF Dispatcher作为一个在界面操作和更新时被UI线程关联的唯一对象,起了一个非常重要的作用。他可以帮助我们实现按序排列的工作项队列。
首页 新闻资讯 行业资讯 WPF Dispatcher在界面操作中作用体现

对于一个开发人员来说,可能在开发一个程序的时候对图形界面的要求并不是很高,因为他们不是美工。那么,使用了WPF后,开发人员可以轻松的实现精美的图形界面。#t#

使用一个专用的 UI 线程来完成界面的操作和更新,这个线程会关联一个***的WPF Dispatcher 对象,用于调度按优先顺序排列的工作项队列。Application.Run() 实际上就是对 Dispatcher.Run() 的间接调用。

WPF Dispatcher通过循环来处理工作项队列,这个循环通常被成为 "帧 (DispatcherFrame)"。Dispatcher.Run() 创建并启动这个帧,这也是 Application.Run() 启动消息循环的最终途径。

 

复制

public sealed class Dispatcher  {  [SecurityCritical, 
UIPermission(SecurityAction.
LinkDemand, Unrestricted=true)]  public static void Run()  {  PushFrame(new DispatcherFrame());  }  } 
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

  • 10.

 

DispatcherFrame 可以嵌套,并通过检查 Continue 属性来决定循环是否继续。我们可以通过调用 Dispatcher.ExitAllFrames() 来终止所有的帧循环,当然这种编程方式并不可取,可能会造成一些意外出现。

与WPF Dispatcher调度对象想对应的就是 DispatcherObject,在 WPF 中绝大部分控件都继承自 DispatcherObject,甚至包括 Application。这些继承自 DispatcherObject 的对象具有线程关联特征,也就意味着只有创建这些对象实例,且包含了 Dispatcher 的线程(通常指默认 UI 线程)才能直接对其进行更新操作。

当我们尝试从一个非 UI 线程更新一个标签,会看到一个如下的异常。

 

复制

private void button1_Click
(object sender, RoutedEventArgs e)  {  new Thread(() => this.label1.
Content
 = DateTime.Now.
ToString()).Start();  } 
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

 

 

按照 DispatcherObject 的限制原则,我们改用 Window.Dispatcher.Invoke() 即可顺利完成这个更新操作。

 

复制

private void button1_Click
(object sender, Routed
EventArgs e)  {  new Thread(() => {  this.Dispatcher.Invoke
(DispatcherPriority.Normal,  new Action(() => this.
label1.Content
 = DateTime.
Now.ToString()));  }).Start();  } 
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

  • 10.

  • 11.

  • 12.

  • 13.

 

如果在其他项目(比如类库)中,我们可以用 Application.Current.Dispatcher.Invoke(...) 完成同样的操作,它们都指向 UI Thread Dispatcher 这个***对象。

WPF Dispatcher还提供了 BeginInvoke 这个异步版本。

 

复制

private void button1_Click(object 
sender, RoutedEventArgs e)  {  new Thread(() => {  Application.Current.Dispatcher.
BeginInvoke(DispatcherPriority.Normal,  new Action(() => {  Thread.Sleep(3000);  this.label1.Content = 
DateTime.Now.ToString();  }));  MessageBox.Show("Hi!");  }).Start();  } 
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

  • 10.

  • 11.

  • 12.

  • 13.

  • 14.

  • 15.

  • 16.

 

凡事都有例外,WPF 还提供了一种继承自 Freezable 的类型,尽管 Freezable 也间接继承自 DispatcherObject,但当诸如WPF Dispatcher这类对象从修改状态变成冻结状态时,它即变成自由线程对象,不在具有线程关联。

15    2009-12-29 14:00:02    WPF Dispatcher