MVVM Light DispatcherHelper,MVVM Light中多线程的正确方法

时间:2018-09-27 07:22:46

标签: multithreading asynchronous mvvm mvvm-light dispatcher

使用MVVM Light进行多线程处理的推荐方法是什么。 我有一个模型,该模型具有布尔属性Busy

 public bool Busy
    {
        get { return busy_; }
        set
        {
           Set(nameof(Busy), ref busy_, value, broadcast: true);
        }
    }

我的视图模型直接为视图发布模型(该模型是继承MVVM Light的ViewModelBase),因此视图直接绑定到模型的busy属性。

如果我总是从UI线程调用模型,那么一切都很好。但是,如果我在视图模型中执行以下操作,则它可能会在其他线程上执行

Task.Factory.StartNew(() => 
{            
  model_.SomeFunctionThatWillSetBusyDuringItsExecution();
});

然后,当然是从非UI线程设置“忙”,然后绑定失败并且应用程序崩溃。如果我碰巧在属性设置器中使用Messenger,似乎Messenger也不会自动将Messenger处理程序代码分派到UI线程。

我意识到MVVM Light中有一个DispatcherHelper,但对于绑定似乎没有帮助。如果我将属性更改为

    public bool Busy
    {
        get { return busy_; }
        set
        {
           DispatcherHelper.CheckBeginInvokeOnUI(() =>
           {
              Set(nameof(Busy), ref busy_, value, broadcast: true);
           });
        }
    }

我仍然遇到异常,由于绑定源不在正确的线程上,导致应用程序崩溃。所以我的问题很简单,在MVVM Light中进行这种多线程处理的推荐方法是什么?

我也尝试过使用syncronizationContext。

           syncContext_.Post(() =>
           {
              Set(nameof(Busy), ref busy_, value, broadcast: true);
           }, null);

如果调用始终来自非UI线程,则该方法有效。如果调用已经从UI线程进行,则syncContext.Post导致在ViewModel方法中的所有代码完成之前才调用Set()函数。这意味着可能无法为其余代码正确更新繁忙状态。因此,这不是理想的解决方案。

感谢您在此主题上的帮助。

1 个答案:

答案 0 :(得分:0)

我没有在属性中添加DispatcherHelper代码,而是在修改属性的所有位置添加了它。这样看来效果很好。

唯一的问题是,由于有人将工作分配给UI线程,因此,如果部分视图模型方法已在UI线程上运行,则ViewModel中的代码将不会获得更新状态。我找到了一种方法,可以确保UI线程处理其Messenger队列,尽管要确保它的更新状态为Busy。它不是最好的解决方案,由于所有上下文切换,它可能会对性能产生不良影响,但至少它可以起作用,并且它是一个简单的方法。

强制UI线程处理其队列中所有消息的代码

  DispatcherHelper.UIDispatcher.Invoke(new Action(() => { }), DispatcherPriority.ContextIdle, null);

如果有更好的解决方法,请告诉我。否则,我将在几天后将其设置为答案。