http://www.haogongju.net/art/17932
最近使用WPF来构建桌面程序,其中要求是:
1. 界面与后台程序使用不同线程,以便在后台运行耗时计算时界面依然响应。
2. 后台程序需要控制界面某些元素,如显示和修改值。
3. 后台程序执行中,需要获取界面把某些用户输入,如用户输出某字符串来继续执行。
然后开始设计,编码测试,过程如下:
对于第1个要求,根据以前的编程经验(Qt,GTK...),果断使用System.Threading.Thread来Start一个线程,与WPF界面线程分开,嗯。
对于第2个要求,使用DataBinding,把WPF界面的类的DataContext设置成给线程用的类里,绑定值,就很容易做到在第二个线程修改值直接反应到WPF的界面上。但对于切换界面(如修改MainWindow的Content给另外一个UserControl),搞得非常麻烦。想过通过绑定Visibility属性,添加IsVisibilityChange方法来做,效果都非常差。从MSDN看WPF多线程的例子
http://msdn.microsoft.com/en-us/lib...改WPF的元素了。
接着第3个要求,考虑到.Net有ManualResetEvent(或者AutoResetEvent)这个很方便的类,果断写下这个UserInput类(暂时使用string来作为用户输入的表现)。
然后在后台线程调用WaitInput,这下麻烦出来了,WPF界面线程也一起Block掉了。
于是不停的修改代码,尝试网上搜索到的方法,均不能解决。 然后回头再仔细看MSDN关于WPF多线程的例子,每一个字都认真的读,发现Dispatcher是唯一的多线程可以修改WPF元素的类。那不知道我在另 外一个线程来调用Dispatcher.BeginInvoke来修改WPF元素可否?立即编写代码尝试。结果是可行的。最终程序结构如下:
整个程序只有一个Window类,那就是从Window派生出来的MainWindow。定义若干UserControl与之相关的Presenter类(用于数据绑定和界面切换),并在MainWindow构造函 数里一一生成并绑定,所有的Presenter有Dispatcher属性,所有的Presenter有若干delegate用于数据绑定不能实现的操作 (定义一个基类即可),如更改MainWindow的Content,并在各个UserControl里定义相应的函数,赋于这些delegate,在 Presenter调用这些delegate的时候,使用Dispatcher.BeginInvoke来调用。初始Content为某一 UserControl。使用BackgroundWorker来启动后台线程,定义一个带ManualResetEvent的UserInput来给线 程得到WPF输入。
这个后台线程就可以随时得到用户的输入,如用户想切换到某个特定界面, 后台线程得到这个输入后可以很方便的切换界面。