Как ViewModel может знать, когда обновляются данные в сервисе? - PullRequest
3 голосов
/ 14 марта 2009

В моем приложении у меня есть несколько моделей ViewModel, которые имеют один сервис (репозиторий, DAO и т. Д.), Назовем его WidgetService , внедренный в них.

Скажем, один из этих ViewModels - это список всех пользовательских виджетов. Другой может быть ViewModel для редактирования / создания одного из этих виджетов.

Пользователь может просмотреть список виджетов в WidgetListView , поддерживаемом WidgetListViewModel , и нажать кнопку, чтобы добавить новый виджет. Чтобы создать этот новый виджет, CreateWidgetViewModel был обновлен и внедрен в DataContext некоторого UserControl / Window, таким образом, посредством волшебства DataTemplates, отображающего CreateWidgetViewModel в CreateWidgetView . Кроме того, обновление CreateWidgetViewModel не обязательно происходит в рамках WidgetListViewModel .

Когда WidgetListViewModel было внедрено с экземпляром WidgetService . CreateWidgetViewModel был внедрен с тем же WidgetService экземпляром.

Теперь, когда пользователь нажимает save в CreateWidgetView , Save метод WidgetService будет вызван и виджет будет быть настойчивым. Теперь WidgetListViewModel необходимо уведомить о появлении нового виджета!

Длинное наращивание приводит к следующему вопросу: как я могу сообщить WidgetListViewModel , что ему нужно отобразить новый виджет?

Я видел Видео , в котором парень из Microsoft делает подобные вещи, используя событие в службе, на которую подписывается ViewModel. Однако недостатком этого является то, что если служба переживает модель представления, тогда модель представления не получит GC'd до тех пор, пока служба не станет GC'd. Я мог бы добавить IDisposable к ViewModel. Но тогда когда / как вызывать Dispose, когда ViewModel представлена ​​только в пользовательском интерфейсе через DataTemplates?

У кого-нибудь есть предложения по этому поводу?

Чтобы уточнить, я бы сказал, что моя интерпретация MVVM наиболее близка к интерпретации Джоша Смита. По крайней мере, в той степени, в которой моя архитектура MVVM довольно близко совпадает с той, что была в источнике Crack.Net.

Ответы [ 5 ]

1 голос
/ 14 марта 2009

Используйте Prism (http://www.codeplex.com/CompositeWPF) EventAggregator , который использует шаблон издатель-подписчик, обеспечивая потерю связи между целевыми и исходными элементами. Идеально подходит именно для сценария, который вы описываете.

1 голос
/ 14 марта 2009

Хорошо, учитывая, что пока нет ответов на этот вопрос, я подумал, что попробую, но я не эксперт по MVVM.

События, кажется, способ пойти с этим. Однако, как вы указали, может быть утечка памяти, если служба переживает ViewModel. Лучший способ справиться с этим - использовать слабый слушатель событий.

Слабые события позволяют вам подключиться к событию со слабой ссылкой, чтобы, если исходный объект был GC, источник не поддерживал работу обработчиком события.

0 голосов
/ 24 марта 2009

Я согласен с Кэмероном использовать шаблон WeakEvent. Я создал базовый класс для ViewModel (в моем примере я использую имя PresentationModel), который поддерживает шаблон WeakEvent.

Мой пример проекта может оказаться полезным: http://www.codeplex.com/CompositeExtensions

JBE

0 голосов
/ 15 марта 2009

Есть несколько вариантов:

  1. Используйте ObservableCollection - это, вероятно, самый простой вариант, но вы должны иметь своего рода «главную» коллекцию в модели и иметь привязку пользовательского интерфейса к этой коллекции напрямую, это может быть не «чистая» архитектура MVVM но это, вероятно, самый простой способ сделать работу.

  2. Используйте событие и убедитесь, что вы убираете за собой, что не легко сделать в MVVM.

  3. Используйте какого-нибудь посредника для автоматической очистки событий (как предлагали другие), но не пишите свои собственные, в этом есть много подводных камней, в WPF есть встроенный класс, который делает это, но я забыл имя (если кто-то помнит имя, пожалуйста, оставьте комментарий).

  4. Периодически обновляйте, если класс ViewModel обновляет список каждые X секунд, это единственный способ получать обновления без какого-либо механизма уведомлений, которым вы должны управлять.

0 голосов
/ 14 марта 2009

Я использовал шаблон Observer (он же шаблон публикации / подписки) для решения этой же проблемы. Я сделал класс, который я назвал EventAggregator, который имел все общие методы и члены данных. Я мог бы зарегистрироваться для события в WidgetListViewModel и опубликовать событие «Widget Created» в CreateWidgetViewModel. Вы можете либо иметь WidgetListViewModel для реализации IDisposable (лучше), чтобы отменить регистрацию вашего события, либо вы можете просто отменить его регистрацию в методе Finalize. Это сработало довольно хорошо, и самое приятное то, что двум моделям представлений не нужно было иметь представление друг о друге.

Для чего-то более сложного или если вам нужно поддерживать различия версий между службой и вашим приложением, вы можете реализовать ModelView, который бы обрабатывал подобные вещи, создавая шаблон ваших приложений M-MV-VM-V. Это может показаться немного излишним, но это может значительно облегчить обслуживание определенных классов проблем. Я знаю, что у меня было несколько проектов, в которые я хотел бы вставить MV, потому что перекрестные помехи между виртуальными машинами и кодом отмены только что стали нелепыми.

...