在WPF(Framework框架)中关于Dispatcher的总结
首先,对于WPF应用程序,用于接受输入、处理事件的线程成为UI线程,在UI线程中有一个DIspatcher对象(this.Dispatcher),该对象的作用在于管理UI线程每个执行的工作项,根据每个工作的优先级排队,优先级可以设置。
Dispatcher提供了两个注册工作项的方法:Invoke和BeginInvoke
Invoke方法:这个是同步调用,就是要执行完这个注册的工作项(执行委托)才会返回
BeginInvoke方法: 这是个异步调用,即可返回
我们在设计程序的时候会涉及到某些耗时操作会占用主线程,早成程序卡假死,用户体验感差,这种问题我们就要用到子线程去处理耗时操作,而子线程不能直接修改主线程(UI线程)中创建的对象,必须通过向UI线程中的Dispatcher注册工作项来完成。
例:加载进度条,耗时操作,放在子线程中进行操作
<Window x:Class="DispatcherTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:DispatcherTest"
mc:Ignorable="d"
Title="MainWindow" Height="250" Width="300">
<StackPanel>
<ProgressBar Name="schduleBar" Height="30" Width="250" Margin="20">
</ProgressBar>
<TextBox Name="scheduleNum" Height="20" Width="30" HorizontalAlignment="Center">
0
</TextBox>
<Button Name="btnStart" Content="Start" Height="30" Width="100" Margin="10">
</Button>
<Button Name="btnCancel" Content="Cancel" Height="30" Width="100">
</Button>
</StackPanel>
</Window>
public MainWindow()
{
InitializeComponent();
this.btnStart.Click += BtnStart_Click;
this.btnCancel.Click += BtnCancel_Click;
}
Thread threadStart; //声明线程
private void BtnStart_Click(object sender, RoutedEventArgs e)
{
threadStart = new Thread(DoTask); //创建线程,去更新加载进度条信息及加载数具体数字
threadStart.Start();
}
private void DoTask()
{
int maxValue = 100;
for(int i =0; i<maxValue; i++)
{
Thread.Sleep(100);
this.Dispatcher.BeginInvoke((Action)delegate () //向Dispatcher里注册工作方法
{
this.schduleBar.Value = i;
this.scheduleNum.Text = i.ToString();
});
}
this.Dispatcher.Invoke((Action)delegate () //从子线程又回到主线程
{
MessageBox.Show("加载完成"); //主线程弹窗,必须关掉MessageBox才能后续操作
});
}
private void BtnCancel_Click(object sender, RoutedEventArgs e)
{
threadStart.Abort(); //中止线程
MessageBox.Show("取消加载,恢复默认","提示");
this.schduleBar.Value = 0;
this.scheduleNum.Text = null;
}
其中,在线程中的委托事件DoTask()中是在开启子线程中操作的,
this.Dispatcher.Invoke((Action)delegate ()
{
MessageBox.Show("加载完成"); //主线程弹窗,必须关掉MessageBox才能后续操作
});
this.Dispatcher.Invoke((Action)delegate (),又回到主线程的同步调用,(必须关闭掉MessageBox才能回到主线程),才能点Cancel按钮/拖动主界面;
若代码改为异步调用, this.Dispatcher.BeginInvoke((Action)delegate ()
this.Dispatcher.BeginInvoke((Action)delegate ()
{
MessageBox.Show("加载完成"); //主线程弹窗,必须关掉MessageBox才能后续操作
});
则可以点击Cancel按钮/拖动主界面;
Invoke方法:这个是同步调用,就是要执行完这个注册的工作项(执行委托)才会返回
BeginInvoke方法: 这是个异步调用,即可返回