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线程!