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效率要更高一點。反應更靈敏。