最近遇到一个问题,在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