Неправильно ли использовать Диспетчер в моей модели ViewModel?

Я конвертирую чат-парсер для игры, в которую играю, я писал в c # winforms для wpf, главным образом, чтобы получить лучший дескриптор MVVM и wpf. Ниже приведен пример того, как мой проект настроен

View : На данный момент это просто простой ListBox с ItemSource, привязанный к моим наблюдаемым моделям наблюдаемой чатовой коллекции

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

public event Action IncomingChat; 

Я использую фона рабочего, чтобы запустить событие в моем backgroundworkers progresschaged событие, потому что, когда я использовал таймер, я продолжал получать проблемы с streamами. Сначала я исправил это, изменив мой таймер на DispatchTimer, но мне не показалось, что у меня есть DispatchTimer в моей модели.

ViewModel : Поскольку у меня есть несколько символов, я создаю несколько ChatViewModels. Я передаю персонажа в конструктор ChatViewModels и подписываюсь на событие чата. Я создаю ObservableColleciton, чтобы держать мои строки чата, когда это событие получено. Теперь я получаю проблему с streamами на моем модуле viewModel, когда пытаюсь добавить строку, которую я получаю от своего события чата, к моему наблюдаемому коллекциям.

Я обошел это, сделав так, чтобы мои viewmodels входящего обработчика событий в чате выглядели так

 public ObservableCollection<Game.ChatLine) Chat {get; private set;} void Chat_Incoming(Game.ChatLine line) { App.Current.Dispatcher.Invoke(new Action(delegate { Chat.Add(line) }), null); } 

Однако это мне не нравится. Хотя это работает, использование Диспетчера в моей модели просмотра, как это кажется мне неуместным.

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

Это не совсем необоснованный подход, и это подход, который принимают многие люди. Лично, если вы используете WPF (или Silverlight 5) и имеете доступ к TPL, я предпочитаю использовать TPL для этого.

Предполагая, что ваша ViewModel построена на streamе пользовательского интерфейса (то есть: по представлению или в ответ на связанное с View событие), что почти всегда относится к IMO, вы можете добавить это в свой конструктор:

 // Add to class: TaskFactory uiFactory; public MyViewModel() { // Construct a TaskFactory that uses the UI thread's context uiFactory = new TaskFactory(TaskScheduler.FromCurrentSynchronizationContext()); } 

Затем, когда вы получите свое событие, вы можете использовать его для его маршала:

 void Chat_Incoming(Game.ChatLine line) { uiFactory.StartNew( () => Chat.Add(line) ); } 

Обратите внимание, что это немного отличается от вашего оригинала, поскольку он больше не блокирует (это больше похоже на использование BeginInvoke вместо Invoke ). Если вам нужно это заблокировать, пока пользовательский интерфейс не завершит обработку сообщения, вы можете использовать:

 void Chat_Incoming(Game.ChatLine line) { uiFactory.StartNew( () => Chat.Add(line) ).Wait(); } 

Модель просмотра – хорошее место для синхронизации streamов. Удалите DispatcherTimer из вашей модели и дайте VM обработать его.

Я обожаю ответ Рида и соглашусь с вашими опасениями, что что-то не так с вашим использованием Dispatcher . Ваше App VM ссылается на App , которое, на мой взгляд, ссылается на артефакт пользовательского интерфейса (или элемент управления). Используйте Application или, еще лучше, вставьте правильный экземпляр Dispatcher в вашу виртуальную машину, что позволяет избежать необходимости создания экземпляра вашей виртуальной машины в streamе пользовательского интерфейса.

  • События WPF в ResourceDictionary для ControlTemplate
  • Как я могу уменьшить код привязки RadioButton?
  • Где Application.DoEvents () в WPF?
  • Получение каталога приложения из приложения WPF
  • Как создать окно WPF без frameworks, которая может быть изменена только с помощью захвата?
  • При создании нового графического интерфейса WPF является предпочтительным выбором для Windows Forms?
  • Разница между {Binding PropertyName} и {Binding Path = PropertyName}
  • Изображение кнопки мыши WPF
  • Как вы полностью удаляете границу кнопки в wpf?
  • Почему обертки свойств .NET обойдены во время выполнения при настройке свойств зависимостей в XAML?
  • Разница между TargetType = "controlType" и TargetType = "{x: Тип controlType}"
  • Давайте будем гением компьютера.