WPF的应用程序运行时,就有一个主线程(UI线程)和其他的一些子线程。
子线程是不能修改UI线程,必须通过UI线程的Dispatcher来完成。
简单点来说:子线程是不能修改程序UI的,除非用UI线程的Dispatcher来注册。
例如:
private void Invoke_Button(object sender, RoutedEventArgs e)
{
Task.Run(() =>
{
Thread.Sleep(1000);
this.TextBlock.Text = "10";
});
}
另起一个线程去修改UI上TextBlock控件的值。就会报异常:System.InvalidOperationException: '调用线程无法访问此对象,因为另一个线程拥有该对象。'
Dispatcher两种注册方式:
Invoke:同步调用,即会在子线程执行完成后返回。
private void Invoke_Button(object sender, RoutedEventArgs e)
{
Task.Run(() =>
{
Dispatcher.Invoke(() =>
{
Thread.Sleep(5000);
this.TextBlock.Text = "10";
});
});
}
BeginInvoke:异步调用,即立即返回。
private void BeginInvoke_Button(object sender, RoutedEventArgs e)
{
Task.Run(() =>
{
Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
{
this.TextBlock.Text = "3";
Thread.Sleep(10000);
}));
});
}
总结:当在子线程中调用Dispather注册时,Dispatcher中的Action依然还是占用着UI线程,所以Dispatcher的工作项依然是越少越少,耗时操作越少越好。
BeginInvoke效率要更高一点。反应更灵敏。