首先,我们要知道两个概念。
一,WPF中有两个线程,一个用于界面UI的管理,一个用于图形的绘制与渲染(Render),
二,在UI线程中,使用了一个名为Dispatcher的类帮助UI线程处理任务。
下面这个例子

using System;
using System.Windows;
using System.Threading;
namespace WpfApplication1
{
/// <summary>
/// Window1.xaml 的交互逻辑
/// </summary>
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
//错误的写法:直接更新
new Thread(() =>
{
progressBar1.Value = 20;
}).Start();
}
private void button2_Click(object sender, RoutedEventArgs e)
{
//正确的写法:通知主线程去完成更新
new Thread(()=>{
this.Dispatcher.Invoke(new Action(()=>{
progressBar1.Value=20;
}));
}).Start();
}
}
}
Dispatcher,翻译过来是调度员的意思。所有控件都有Dispatcher属性,因为在WPF中,控件都是继承于DispatcherObject类,DispatcherObject暴露了Dispatcher属性用来取得创建对象线程对应的Dispatcher,我们通过Dispatcher直接调用Invoke或者BeginInvoke来投入任务。
同时,Dispatcher本身是一个单例模式,它被用于获得当前线程的Dispatcher。所以,无论我们使用哪个Dispatcher,其实都是在调用同一个UI线程,即本文开头所说的那个UI线程来处理任务。
Dispatcher暴露了两个方法,Invoke和BeginInvoke,这两个方法还有多个不同参数的重载。其实本质上,Invoke内部还是调用了BeginInvoke,区别在于后者是异步执行的,一个典型的BeginInvoke参数如下:
public DispatcherOperation BeginInvoke(Delegate method, DispatcherPriority priority, params object[] args);
DispatcherPriority定义了很多优先级,WPF将这些优先级主要分成两类。前台优先级和后台优先级,其中前台包括Loaded~Send,后台包括Background~Input。
给个例子:
namespace WpfApplication1
{
public class WindowHelper
{
public static void SomeMethod() {
var task = Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
Application.Current.MainWindow.Title = "我修改过的窗体标题"; }));
task.Completed += new EventHandler(task_Completed);
}
static void task_Completed(object sender, EventArgs e)
{
MessageBox.Show("任务已经完成");
}
参考文献:
https://www.cnblogs.com/chenxizhang/archive/2010/03/25/1694604.html
http://www.cnblogs.com/Zhouyongh/archive/2009/08/31/1557126.html