WPF/многопоточность: Диспетчер интерфейса в MVVM

Так сказать в среде MVVM, я в фоновом потоке, и я хотел бы запустить обновление на элементе управления ui. Так что обычно я бы пошел myButton.Dispatcher.BeginInvoke(blabla), но у меня нет доступа к myButton (потому что в viewmodel нет доступа к элементам управления представлением). Итак, какова нормальная модель для этого?

(я предполагаю, что он всегда привязан, но я хотел бы знать, как это сделать через диспетчер)

Ответы

Ответ 1

Я обычно использую Application.Current.Dispatcher: поскольку Application.Current является статическим, вам не нужна ссылка на элемент управления

Ответ 2

Из Caliburn Micro исходный код:

public static class Execute
{
    private static Action<System.Action> executor = action => action();

    /// <summary>
    /// Initializes the framework using the current dispatcher.
    /// </summary>
    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);
        };
    }

    /// <summary>
    /// Executes the action on the UI thread.
    /// </summary>
    /// <param name="action">The action to execute.</param>
    public static void OnUIThread(this System.Action action)
    {
        executor(action);
    }
}

Прежде чем использовать его, вы должны будете вызвать Execute.InitializeWithDispatcher() из потока пользовательского интерфейса, тогда вы можете использовать его следующим образом: Execute.OnUIThread(()=>SomeMethod())

Ответ 3

ViewModelBase Catel имеет свойство Dispatcher, которое вы можете использовать.

Ответ 4

Я предпочитаю, чтобы мои объекты ViewModels наследовали от DependencyObject и гарантировали, что они построены на потоке пользовательского интерфейса, что прекрасно справляется с этой ситуацией - они имеют свойство Dispatcher, которое соответствует диспетчеру потоков пользовательского интерфейса. Затем вам не нужно загрязнять ваше представление деталями реализации ViewModel.

Некоторые другие плюсы:

  • Ед. тестируемость: вы можете unit test их без запуска приложения (а не полагаться на Application.Current.Dispatcher)
  • Свободная связь между View и ViewModel
  • Вы можете определить свойства зависимостей в ViewModel и не писать код для обновления представления при изменении этих свойств.

Ответ 5

Вы можете поднять событие в своей модели просмотра (возможно, используя соглашение об именах, чтобы указать, что он будет поднят из потока, отличного от UI, например NotifyProgressChangedAsync). Тогда ваш View, который подключен к событию, может обращаться с диспетчером соответствующим образом.

Или вы можете передать делегат функции синхронизации в вашу модель просмотра (из вашего представления).

Ответ 6

Передайте диспетчер потоков пользовательского интерфейса в конструктор ViewModel и сохраните его в виртуальной машине.

Обратите внимание, что каждый поток может иметь свой собственный диспетчер. Вам понадобится поток пользовательского интерфейса!