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:
后台代码:
ChildWindow类:
运行效果
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(); } }
运行效果
相关文章推荐
- C#及WPF获取本机所有字体和颜色的方法
- WPF MVVM示例讲解
- WPF实现时钟特效
- PowerShell中调用WPF生成炫酷窗口实例
- C#中Invoke 和 BeginInvoke 的真正涵义
- WPF实现类似360安全卫士界面的程序源码分享
- C#中WPF使用多线程调用窗体组件的方法
- WPF实现渐变淡入淡出的登陆窗口效果
- WPF的数据绑定详细介绍
- WPF绑定实例详解
- 关于WPF使用MultiConverter控制Button状态的详细介绍
- 如何搭建新的WPF项目框架
- 超炫酷的WPF实现Loading控件效果
- 解析WPF实现音频文件循环顺序播放的解决方法
- PHP 5.3新增魔术方法__invoke概述
- Java反射机制及Method.invoke详解
- 使用IntelliJ IDEA开发SpringMVC网站(三)数据库配置
- WPF Toolkit - February 2010 Release
- 使用WPF创建一个Digg桌面应用
- Barcode Professional for WPF