WPF中Dispatcher调度程序小探
Dispatcher,即调度程序,在每个线程中都唯一存在,负责线程中数据的各项操作。例如线程A创建了实例I,则线程B就不能直接去更新I,而必须通过线程A来委托处理。下面举个简单的例子。
有如下简单的XAML代码,一个Label用于显示,两个Button用于更新Label数据:
代码
<Grid>
<Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="129,147,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click" />
<Label Content="Label" Height="28" HorizontalAlignment="Left" Margin="129,69,0,0" Name="label1" VerticalAlignment="Top" Width="207" />
<Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="244,147,0,0" Name="button2" VerticalAlignment="Top" Width="75" Click="button2_Click" />
</Grid>
在button1中:
private void button1_Click(object sender, RoutedEventArgs e)
{
label1.Content = "Updated by button1.";
}
很显然这样可以更新label1中的数据,因为label1,button1,button2都是窗口创建时由主线程创建的,所以它们的 Dispatcher是一样的。但是假如我们在点击之后创建一个新的线程去更新label1会发生什么呢?不妨试试!
代码
private void button2_Click(object sender, RoutedEventArgs e)
{
Thread updateThread = new Thread(UpdateLabel);
updateThread.Start();
}
private void UpdateLabel()
{
label1.Content = "Updated by button2.";
}
当我们点击button2,铛铛铛铛~~
O了,没有权限!那就对了!下面给出解决的方法,其实原理很简单,你不让我访问,那我告诉你该这么做,你自己去做呗~~
代码
private void button2_Click(object sender, RoutedEventArgs e)
{
Thread updateThread = new Thread(UpdateLabel);
updateThread.Start();
}
private delegate void UpdateLabelDelegate();
private void UpdateLabel()
{
label1.Dispatcher.Invoke(new UpdateLabelDelegate(UpdateLabelAction));
}
private void UpdateLabelAction()
{
label1.Content = "Updated by button2.";
}
首先定义一个托管UpdateLabelDelegate,你也尽可以创建一个带参数的托管。 label1.Dispatcher就是调用label1的调度程序,它当然有操作label1的权限,然后通过Invoke函数调用托管函数,就是这么简单!(Invoke方法是同步操作,还有一个异步操作BeginInvoke)
第一次在园子里发文,希望大家多指教!