MVVM Light DispatcherHelper, правильный способ многопоточности в MVVM Light - PullRequest
0 голосов
/ 27 сентября 2018

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

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

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

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

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);

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

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

1 Ответ

0 голосов
/ 27 сентября 2018

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

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

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

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

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

...