MVVM Light DispatcherHelper, правильный способ многопоточности в MVVM Light

Каков рекомендуемый способ многопоточности с MVVM Light. У меня есть модель с логическим свойством Busy

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

Моя модель представления публикует модель непосредственно для представления (модель наследует ViewModelBase MVVM Light), поэтому представление привязывается непосредственно к свойству Busy модели.

Если я всегда вызываю модель из потока пользовательского интерфейса, все хорошо. Но если я сделаю следующее в своей модели представления, чтобы она могла выполняться в другом потоке

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

Затем, конечно, Busy устанавливается из потока, отличного от пользовательского интерфейса, а затем происходит сбой привязки и сбой приложения. Если мне случится использовать Messenger в установщике свойств, кажется, что Messenger автоматически не отправляет код обработчика Messenger в поток пользовательского интерфейса.

Понял, что в 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);

Это работает, если вызов всегда происходит из потока, отличного от пользовательского интерфейса. Если вызов уже из потока пользовательского интерфейса, syncContext.Post приводит к тому, что функция Set() не вызывается до тех пор, пока весь код в методе ViewModel не завершится. Это означает, что состояние занятости для оставшегося кода может быть обновлено неправильно. Так что это не идеальное решение.

Я благодарен за помощь в этой теме.


person Johan    schedule 27.09.2018    source источник
comment
Я думаю, проблема в том, что ваш метод доступа Set не должен выполнять такую ​​операцию. Я считаю, что здесь проблема дизайна. Для вашего IsBusy должно быть установлено значение false/true только для некоторого события/условия вашего метода потока (в потоке пользовательского интерфейса). Таким образом, вам даже не придется беспокоиться о DispatcherHelper или проблемах с доступом к потоку. Метод потока всегда должен быть изолирован и сообщать только о состоянии начала/окончания и обновлении хода выполнения, и все это всегда должно происходить в основном потоке/потоке пользовательского интерфейса.   -  person Luishg    schedule 09.04.2019


Ответы (1)


Вместо добавления кода DispatcherHelper внутрь свойства я добавил его во все места, где свойство было изменено. Тогда это, кажется, работает хорошо.

Единственная проблема, поскольку одна отправка работы в поток пользовательского интерфейса, код в ViewModel не получит обновленное состояние, если часть метода модели представления уже выполняется в потоке пользовательского интерфейса. Я нашел способ заставить поток пользовательского интерфейса обрабатывать свою очередь сообщений, убедившись, что он получил обновленное состояние «Занят». Это не самое лучшее решение, и оно, вероятно, плохо скажется на производительности из-за переключения контекста, но, по крайней мере, оно работает, и это простой один лайнер.

Код, чтобы заставить поток пользовательского интерфейса обрабатывать все сообщения в своей очереди

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

Если есть более оптимальный способ решения, дайте, пожалуйста, знать. В противном случае я установлю это как ответ через несколько дней.

person Johan    schedule 27.09.2018