WPF /multithreading:MVVM中的UI调度程序
所以说在MVVM环境中,我在后台线程中,我想在ui控件上运行更新。 所以通常我会去myButton.Dispatcher.BeginInvoke(blabla),但是我无法访问myButton(因为viewmodel无法访问视图的控件)。 那么这样做的正常模式是什么?
(我想总是有约束力,但我想通过调度员知道如何做到这一点)
我通常使用Application.Current.Dispatcher
:因为Application.Current
是静态的,所以你不需要对控件的引用
来自Caliburn Micro源代码:
public static class Execute { private static Action executor = action => action(); /// /// Initializes the framework using the current dispatcher. /// public static void InitializeWithDispatcher() { #if SILVERLIGHT var dispatcher = Deployment.Current.Dispatcher; #else var dispatcher = Dispatcher.CurrentDispatcher; #endif executor = action =>{ if(dispatcher.CheckAccess()) action(); else dispatcher.BeginInvoke(action); }; } /// /// Executes the action on the UI thread. /// /// The action to execute. public static void OnUIThread(this System.Action action) { executor(action); } }
在使用它之前,你必须从UI线程调用Execute.InitializeWithDispatcher()
然后你可以像这样使用它执行Execute.OnUIThread(()=>SomeMethod())
Catel的ViewModelBase有一个可以使用的Dispatcher属性。
我倾向于让我的ViewModelinheritance自DependencyObject并确保它们是在UI线程上构建的,这使得它们能够完美地处理这种情况 – 它们具有与UI线程的调度程序相对应的Dispatcher
属性。 然后,您不需要使用ViewModel的实现细节污染您的视图。
其他一些优点:
- 单元可测试性:您可以在没有正在运行的应用程序的情况下对这些进行unit testing(而不是依赖于
Application.Current.Dispatcher
) - View和ViewModel之间的松散耦合
- 您可以在ViewModel上定义依赖项属性,并且不会编写代码来更新视图,因为这些属性会更改。
您可以在View Model上引发一个事件(可能使用命名约定来指示它将从非UI线程引发 – 例如NotifyProgressChangedAsync)。 然后您的View附加到事件可以适当地处理调度员。
或者,您可以将委托传递给View Model的同步function(从您的View中)。
将UI线程的调度程序传递给ViewModel的构造函数并将其存储在VM中。
请注意,每个线程可能都有自己的调度程序。 你将需要UI线程!