В MVVM должен ViewModel или Model реализовать INotifyPropertyChanged? - PullRequest
154 голосов
/ 21 апреля 2009

Большинство примеров MVVM, с которыми я работал, имели Model , реализующую INotifyPropertyChanged, но в Пример CommandSink Джоша Смита ViewModel реализует INotifyPropertyChanged .

Я все еще когнитивно собираю концепции MVVM, поэтому не знаю, если:

  • Вы должны поместить INotifyPropertyChanged в ViewModel, чтобы заставить CommandSink работать
  • это просто отклонение от нормы, и это на самом деле не имеет значения
  • у вас всегда должна быть модель, реализующая INotifyPropertyChanged, и это просто ошибка, которая будет исправлена, если она будет разработана из примера кода для приложения

Каким был опыт других в проектах MVVM, над которыми вы работали?

Ответы [ 17 ]

134 голосов
/ 10 мая 2010

Я категорически не согласен с концепцией, согласно которой Модель не должна реализовывать INotifyPropertyChanged. Этот интерфейс не зависит от пользовательского интерфейса! Это просто сообщает об изменении. Действительно, WPF интенсивно использует это для выявления изменений, но это не значит, что это интерфейс пользовательского интерфейса. Я бы сравнил это со следующим комментарием: « Шина - это автомобильный аксессуар ». Конечно, но велосипеды, автобусы и т. Д. Тоже им пользуются. Итак, не воспринимайте этот интерфейс как интерфейс.

Сказав это, это не обязательно означает, что я считаю, что Модель должна предоставлять уведомления. Фактически, как правило, модель не должна реализовывать этот интерфейс, за исключением случаев, когда это необходимо. В большинстве случаев, когда данные сервера не передаются в клиентское приложение, модель может устареть. Но если слушать данные финансового рынка, то я не понимаю, почему модель не может реализовать интерфейс. Например, что если у меня есть логика, не связанная с пользовательским интерфейсом, например, служба, которая, когда она получает цену Bid или Ask для данного значения, выдает предупреждение (например, по электронной почте) или размещает заказ? Это может быть возможным чистым решением.

Тем не менее, существуют разные способы достижения цели, но я бы всегда выступал за простоту и избегал избыточности.

Что лучше? Определить события в коллекции или изменениях свойств в модели представления и распространить их на модель или иметь представление, чтобы обновить модель (через модель представления)?

Суть в том, что когда вы видите, что кто-то заявляет, что " вы не можете сделать то или это ", это признак того, что он не знает, о чем говорит.

Это действительно зависит от вашего случая, и на самом деле MVVM - это фреймворк с множеством проблем, и мне еще предстоит увидеть общую реализацию MVVM по всем направлениям.

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

99 голосов
/ 21 апреля 2009

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

Я уверен, что другие не согласятся, но я так работаю.

28 голосов
/ 04 мая 2009

В M-V-VM ViewModel всегда (модель не всегда) реализует INotifyPropertyChanged

Ознакомьтесь с шаблоном / инструментарием проекта M-V-VM из http://blogs.msdn.com/llobo/archive/2009/05/01/download-m-v-vm-project-template-toolkit.aspx. Он использует DelegateCommand для командования и должен стать отличным стартовым шаблоном для ваших проектов M-V-VM.

11 голосов
/ 01 января 2011

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

Если вы рассматриваете модель представления как нечто большее, чем DataController, и реализуете архитектуру, в которой ваш DataController является единственным элементом, который касается данных, то вы никогда не коснетесь данных напрямую, но всегда будете использовать DataController. DataController полезен для пользовательского интерфейса, но не обязательно только для пользовательского интерфейса. Он предназначен для бизнес-уровня, пользовательского интерфейса и т. Д. ...

DataModel -------- DataController ------ View
                  /
Business --------/

У вас получается такая модель. Даже бизнес должен касаться только данных, используя ViewModel. Тогда ваша загадка просто уходит.

8 голосов
/ 21 апреля 2009

Это зависит от того, как вы реализовали свою модель. Моя компания использует бизнес-объекты, подобные объектам Lhotka CSLA, и широко использует INotifyPropertyChanged во всей бизнес-модели.

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

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

3 голосов
/ 15 декабря 2015

Я согласен с ответом Пауло, использование INotifyPropertyChanged в моделях полностью приемлемо и даже предлагается Microsoft -

Как правило, модель реализует средства, облегчающие привязать к виду. Обычно это означает, что он поддерживает свойство и коллекция изменила уведомление через INotifyPropertyChanged и INotifyCollectionChanged интерфейсы. Модели классов, которые представляют коллекции объектов, как правило, происходят от ObservableCollection<T> класс, который обеспечивает реализацию INotifyCollectionChanged интерфейс.

Хотя вам решать, хотите ли вы этот тип реализации или нет, но помните -

Что если в ваших модельных классах не реализованы необходимые интерфейсы?

Иногда вам придется работать с объектами модели, которые не реализовать INotifyPropertyChanged, INotifyCollectionChanged, IDataErrorInfo или INotifyDataErrorInfo интерфейсы. В этих случаях модель представления, возможно, должна обернуть объекты модели и выставить необходимые свойства для просмотра. Значения этих свойств будут предоставляться непосредственно объектами модели. Модель представления будет реализовать необходимые интерфейсы для свойств, которые он выставляет так что представление может легко привязать к ним данные.

Взято из - http://msdn.microsoft.com/en-us/library/gg405484(PandP.40).aspx

Я работал в некоторых проектах, где мы не реализовали INotifyPropertyChanged в наших моделях, и из-за этого мы столкнулись с множеством проблем; В VM было необходимо ненужное дублирование свойств, и в то же время нам пришлось обновить базовый объект (с обновленными значениями), прежде чем передавать их в BL / DL.

Вы столкнетесь с проблемами, особенно если вам нужно работать с коллекцией объектов вашей модели (скажем, в редактируемой сетке или списке) или со сложными моделями; объекты модели не будут обновляться автоматически, и вам придется управлять всем этим в вашей виртуальной машине.

3 голосов
/ 24 августа 2013

Я думаю, что ответ достаточно ясен, если вы хотите придерживаться MV-VM.

см: http://msdn.microsoft.com/en-us/library/gg405484(v=PandP.40).aspx

В шаблоне MVVM представление инкапсулирует UI и любую логику UI, модель представления инкапсулирует логику и состояние представления, а модель - бизнес-логику и данные.

"Представление взаимодействует с моделью представления посредством привязки данных, команды и изменения уведомлений. Запросы модели представления, наблюдает и координирует обновления модели, конвертируя, проверка и агрегирование данных по мере необходимости для отображения в представлении. «

3 голосов
/ 10 ноября 2009

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

2 голосов
/ 21 апреля 2009

Я бы сказал, в вашей ViewModel. Это не часть Модели, так как Модель не зависит от пользовательского интерфейса. Модель должна быть «все, кроме бизнес-агностика»

1 голос
/ 19 февраля 2013

Я думаю, что все зависит от варианта использования.

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

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

Поставьте себя на место какой-то модели, которая должна сотрудничать с некоторыми другими моделями. У вас есть различные события, чтобы подписаться. Все они реализованы как INPC. Представьте себе те обработчики событий, которые у вас есть. Один огромный каскад предложений if и / или предложений switch.

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

Давайте посмотрим на 2 разных реализации одной и той же абстракции:

public class ConnectionStateChangedEventArgs : EventArgs
{
    public bool IsConnected {get;set;}
}

interface IConnectionManagerINPC : INotifyPropertyChanged
{
    string Name {get;}
    int ConnectionsLimit {get;}
    /*

    A few more properties

    */
    bool IsConnected {get;}
}

interface IConnectionManager
{
    string Name {get;}
    int ConnectionsLimit {get;}
    /*

    A few more properties

    */
    event EventHandler<ConnectionStateChangedEventArgs> ConnectionStateChanged;
    bool IsConnected {get;}
}

Теперь посмотрите на них обоих. Что говорит IConnectionManagerINPC? Что некоторые из его свойств могут измениться. Вы не знаете, кто из них. Фактически, дизайн таков, что только IsConnected изменяется, так как остальные доступны только для чтения.

Напротив, намерения IConnectionManager ясны: «Я могу вам сказать, что значение моего свойства IsConnected может измениться».

...