WPF / Многопоточность: Диспетчер пользовательского интерфейса в MVVM - PullRequest
16 голосов
/ 07 января 2011

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

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

Ответы [ 6 ]

37 голосов
/ 07 января 2011

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

15 голосов
/ 07 января 2011

С 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())

5 голосов
/ 15 сентября 2011

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

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

  • Тестируемость модулей: вы можете тестировать их без запуска приложения (вместо того, чтобы полагаться на Application.Current.Dispatcher)
  • Слабая связь между View & ViewModel
  • Вы можете определить свойства зависимостей в ViewModel и не писать код для обновления представления при изменении этих свойств.
4 голосов
/ 13 января 2011

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

0 голосов
/ 13 января 2011

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

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

0 голосов
/ 07 января 2011

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...