您的位置:首页 > 其它

WPF 如何在线程中打开子窗体

2016-03-03 20:51 405 查看
    最近遇到一个问题,在wpf程序的某个线程中打开子窗体时显示“调用线程必须为 STA,因为许多 UI 组件都需要”,这是典型的子线程更新UI异常问题了,解决方法是用Dispatcher的invoke方法来执行UI操作。

    Dispatcher的字面意思是“调度员”,很形象地解释了它的作用——处理并发和多线程。Dispatcher本身是一个单例模式,构造函数私有,暴露了一个静态的CurrentDispatcher方法用于获得当前线程的Dispatcher,Dispatcher内部维护了一个静态的 List<Dispatcher> _dispatchers, 每当使用CurrentDispatcher方法时,它会在这个_dispatchers中遍历,如果没有找到,则创建一个新的Dispatcher对 象,加入到_dispatchers中去。Dispatcher内部维护了一个Thread的属性,创建Dispatcher时会把当前线程赋值给这个
Thread的属性,下次遍历查找的时候就使用这个字段来匹配是否在_dispatchers中已经保存了当前线程的Dispatcher。WPF的控件均继承自DispatcherObject,具有线程关联特征,包含了 Dispatcher 的线程(通常指默认 UI 线程)才能对UI控件进行操作。

   回到问题,因为工作线程并不能操作UI,所以出错;这里需要用到Dispatcher的invoke方法或者BeginInvoke方法来解决多线程更新UI问题(Invoke是同步执行,BeginInvoke是异步执行);不过首先须要获取当前AppDomain的Application对象,然后获取与此 DispatcherObject 关联的 Dispatcher。

示例如下:

MainWindow.xaml:

<Window x:Class="DispatcherLearning.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:DispatcherLearning"
Title="MainWindow" Height="325" Width="502">
<Grid>
<Button Name="btn" Content="打开另一个窗体" HorizontalAlignment="Center" VerticalAlignment="Center"  Click="OpenWindow"/>
</Grid>
</Window>


后台代码:

private void OpenWindow(object sender, RoutedEventArgs e)
{
Thread thread = new Thread(() =>
{
Application.Current.Dispatcher.Invoke(new Action(() => { ChildWindow.show("打开了一个新窗体!"); }));
});
thread.IsBackground = true;
thread.Start();
}



ChildWindow类:

public partial class ChildWindow : Window
{
private ChildWindow()
{
InitializeComponent();
}
public static void show(string message)
{
ChildWindow childwin = new ChildWindow();
childwin.messageBlock.Text = message;
childwin.ShowDialog();
}
}



运行效果
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  WPF Dispatcher Invoke