когда использовать Dispatcher в mvvm? - PullRequest
1 голос
/ 28 ноября 2011

После видео Джейсона Долингера я создал DispatchingWcfModel, которая украшает обычную модель.Но я не понимаю, зачем мне это нужно.Должен ли я всегда использовать какую-то диспетчерскую модель?Что если я буду использовать обычную модель вместо диспетчерской?Зачем мне "Диспетчер"?

class DispatchingWcfModel : IWcfModel
{

    private readonly IWcfModel _underlying;
    private readonly Dispatcher _currentDispatcher;

    public DispatchingWcfModel(IWcfModel model)
    {
        _currentDispatcher = Dispatcher.CurrentDispatcher;
        _underlying = model;
        _underlying.DataArrived += _underlying_DataArrived;
    }

    private void _underlying_DataArrived(List<ConsoleData> obj)
    {
        Action dispatchAction = () =>
        {
            if (DataArrived != null)
            {
                DataArrived(obj);
            }
        };
        _currentDispatcher.BeginInvoke(DispatcherPriority.DataBind, dispatchAction);
    }

    public List<ConsoleData> DataList
    {
        get { throw new NotImplementedException(); }
        set { throw new NotImplementedException(); }
    }

    public event Action<List<ConsoleData>> DataArrived;
}

Ответы [ 4 ]

1 голос
/ 28 ноября 2011

TL; DR: DispatchingWcfModel Заключение класса вводится IWcfModel и гарантирует, что при получении новых данных изменения будут отправлены в пользовательский интерфейс безопасным способом. Событие IWcfModel.DataArrived было инициировано вФоновый поток, поэтому DispatchingWcfModel всегда выдвигает обратный вызов с помощью Dispatcher в поток пользовательского интерфейса.

Подробнее: В вашем примере DispatchingWcfModel класс подписывается на событие с внедрением IWcfModel, поэтомукогда событие было инициировано - будет вызван обработчик события _underlying_DataArrived и какой самый важный пункт - он будет вызван в потоке, который фактически вызывает событие, поэтому возможно, что вызывающий поток не будет пользовательским интерфейсомПоток, поэтому любые изменения в элементах управления пользовательского интерфейса будут неудачными, чтобы избежать использования Dispatched.

В WPF Dispatcher полезен, когда вам нужно обновить элементы пользовательского интерфейса, так что это должно быть сделано в потоке пользовательского интерфейса.Правильный способ сделать это - делегировать эту работу Dispatcher, который хранит очередь рабочих элементов (запросов), которые должны быть выполнены на UIThread.

MSDN :

В WPF к DispatcherObject может обращаться только Диспетчер, с которым он связан.Например, фоновый поток не может обновить содержимое Button, связанной с Dispatcher в потоке пользовательского интерфейса.Чтобы фоновый поток мог получить доступ к свойству Content кнопки, фоновый поток должен делегировать работу диспетчеру, связанному с потоком пользовательского интерфейса.Это достигается с помощью Invoke или BeginInvoke.Invoke синхронный, а BeginInvoke асинхронный.Операция добавляется в очередь Dispatcher по указанному DispatcherPriority.

1 голос
/ 28 ноября 2011

Dispatcher - внутренняя очередь сообщений WPF для основного потока пользовательского интерфейса.Его можно использовать из фонового потока для запуска команд в основном потоке пользовательского интерфейса приложения.

Это важно, потому что WPF не позволяет вам получать доступ к объектам, которые были созданы в других потоках.Например, если кнопка создается в главном потоке пользовательского интерфейса, вы не можете изменить эту кнопку из другого потока, но вы можете использовать Диспетчер из другого потока, чтобы отправить команду в основной поток пользовательского интерфейса для обновления кнопки.

Это относится ко всем объектам, а не только к элементам пользовательского интерфейса.Если в одном потоке создается что-то вроде ObservableCollection, другой поток не может его изменить.По этой причине все объекты обычно создаются в основном потоке пользовательского интерфейса.

Сообщения диспетчера могут обрабатываться синхронно или асинхронно.Например,

// Will execute SomeMethod on the main UI thread synchronously
Dispatcher.Invoke(SomeMethod);

// Will execute SomeMethod on the main UI thread asynchronously
Dispatcher.BeginInvoke(SomeMethod);

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

// Will execute SomeMethod on the main UI thread synchronously, 
// at the same priority as Rendering controls
Dispatcher.Invoke(DispatcherPriority.Render, SomeMethod);

// Will execute SomeMethod on the main UI thread asynchronously, 
// at the same priority as background processes
Dispatcher.BeginInvoke(DispatcherPriority.Background, SomeMethod);
0 голосов
/ 28 ноября 2011

Не вдаваясь в технические детали (опишите здесь другие ответы), вы используете Диспетчер, когда

  1. Вы хотите сделать что-то позже
  2. вы хотите что-то сделать в потоке пользовательского интерфейса

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

Нет. 1 немного более неясен, но возможен благодаря перегрузкам BeginInvoke, которые принимают значение DispatcherPriority .

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

0 голосов
/ 28 ноября 2011

Диспетчер используется для доступа к графическим пользовательским элементам.Эти пользовательские элементы создаются в виде диспетчера.Другие темы не имеют доступа к ним.Поэтому, когда вы хотите получить доступ к элементам графического интерфейса, вы должны вызвать операцию диспетчера.

Но модель диспетчеризации, кажется, является неправильным подходом.Эти вещи должны быть сделаны в модели представления.Это одна из причин, почему существует модель представления.Обычно это модель POCO или DTO, поэтому нельзя полагаться на каждую модель, реализующую ваш интерфейс IWcfModel.

Я не знаю видео, о котором вы говорите, но, похоже, что понимание авторами MVVM немного не в порядке.

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