Предоставьте список моделей нескольким ViewModels и синхронизируйте их.

Я знаю, что существует много дискуссий о том, как следует обрабатывать коллекции Model и ViewModel, и от разных сторон было предложено множество «синхронизирующих» решений, а также BLINQ, CLINQ, MVVM Wrapper Kit и т. д. Я до сих пор не понимаю этого, и я хотел бы найти хорошее решение проблем в моем текущем проекте, как описано здесь. Основное отличие состоит в том, что у меня есть несколько ViewModel, которые предоставляют одни и те же данные модели.

У меня довольно простой проект WP7, и я использую MVVM Light и класс Messenger в качестве посредника. Существует список элементов, которые извлекаются из изолированного хранилища. Несколько (четыре) разных представления отображают эти данные в разных формах. Все три из них могут изменять данные по-разному (ViewModel содержит логику для изменения, а не представление).

Если я выберу ObservableCollection‹> в ViewModel, который обертывает List‹> в модели, то ViewModel, которая изменяет данные, изменяет как свою собственную ObservableCollection‹>, так и List‹> в модели. Это, вероятно, то, что я сделал бы, если бы у меня была одна ViewModel, выставляющая список из модели, чтобы ViewModel мог поддерживать себя и модель в актуальном состоянии. Однако в этом проекте у меня есть несколько потребителей одного и того же списка, и ObservableCollections‹> в других ViewModels не будут обновлены. Чтобы исправить эту ситуацию, я могу использовать шаблон посредника и уведомить другие ViewModels об изменении коллекции элементов, чтобы они могли ее обновить. Я мог бы повысить производительность, отправив сообщение с описанием изменения, и все остальные ViewModels могли бы сделать то же самое изменение внутри себя. Однако это потребует, чтобы я разделил часть этой логики в центральном месте, чтобы избежать дублирования логики добавления/удаления/изменения в нескольких разных ViewModels.

Поскольку мне нужно сообщить об изменениях другим ViewModels, я решил пойти другим путем. Я изменил ObservableCollection‹> на стандартный List‹> и удалил код для обработки уведомления об изменении. Таким образом, и ViewModel, и Model имеют объекты List‹>. На самом деле не имеет значения, оборачиваю ли я список моделей в ViewModel или нет, я могу выставить Model.Items непосредственно в ViewModel, чтобы упростить вещи (и, возможно, повысить производительность). Теперь, когда какая-то ViewModel что-то меняет, она изменит это непосредственно в модели, а затем отправит сообщение о том, что коллекция элементов изменилась, и все ViewModels вызывают уведомление об изменении свойства в свойстве коллекции.

Кажется, это работает нормально. Однако у меня есть две проблемы:

  • Это хорошее решение или позже у меня возникнут проблемы? Делаю ли я что-то полностью против MVVM, что в конечном итоге повредит кодовой базе?
  • У меня такое ощущение, что уведомление об изменении иногда немного тормозит. То есть, когда я «щелкаю» элемент в списке, возникает небольшая задержка перед обновлением списка. Я не уверен, связано ли это с тем, что я обновляю весь список i в нескольких представлениях или из-за задержки посредника.

Любые мысли/комментарии приветствуются.


person mikeesouth    schedule 07.11.2010    source источник


Ответы (2)


Отслеживание того, как разные модели представления уведомляют друг друга об изменениях, приведет к спагетти-коду. В настоящее время я сам прохожу через это со сложным настольным приложением Silverlight 4.

Решение, которое я нашел, состоит в том, чтобы иметь отдельную ViewModel, содержащую данные, которые будут совместно использоваться другими вашими ViewModels. Таким образом, у вас есть только один ObservableCollection — тот, который находится в модели представления с вашими данными.

person Matt Casto    schedule 08.11.2010
comment
Хм, интересное решение. Не думал об этом в таком ключе. Возможно, это облегчило бы мою следующую головную боль — анимацию. Я хотел бы анимировать изменения списка (элементы перемещаются вверх/вниз, меняют цвет, добавляются/удаляются и т. д.). Не зная точно, что это было за изменение, я не могу его оживить. Используя уведомление об изменении в ObservableCollection, я мог бы лучше контролировать, какую анимацию запускать в зависимости от изменения. - person mikeesouth; 09.11.2010

Часть решения о том, что делать в этой ситуации, будет зависеть от количества объектов в вашем Списке и количества манипуляций, которые вы с ними делаете. Какой бы подход вы ни выбрали, обязательно тщательно протестируйте его на реальном устройстве, чтобы проверить производительность.

Тем не менее, я склоняюсь к тому, чтобы решить вашу проблему, используя подход, который вы избрали:
- Его простота обеспечивает гибкость в будущем.
- Из-за его простоты другие разработчики должны быть в состоянии понять кодировать легче в будущем.

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

person Matt Lacey    schedule 08.11.2010
comment
Да, я согласен с тем, что с точки зрения производительности абсолютно необходимо, чтобы он хорошо работал на реальном устройстве. Я получу свой телефон на следующей неделе, но до тех пор я постараюсь сделать как можно больше. - person mikeesouth; 09.11.2010