В MVVM должна ли ViewModel или модель реализовать INotifyPropertyChanged?


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

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

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

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

15 147

15 ответов:

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

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

Я категорически не согласен с концепцией, что модель не следует использовать тег INotifyPropertyChanged. Этот интерфейс не является специфичным для пользовательского интерфейса! Он просто информирует об изменениях. Действительно, WPF сильно использует это для идентификации изменений, но это не значит, что это интерфейс пользовательского интерфейса. Я бы сравнил его со следующим комментарием:"шина является автомобильным аксессуаром". Конечно, это так, но велосипеды, автобусы и т. д. также используйте его. В общем, не принимайте этот интерфейс как вещь пользовательского интерфейса.

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

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

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

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

в 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 проектов.

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

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

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

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

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

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

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

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

посмотреть: http://msdn.microsoft.com/en-us/library/gg405484(в=PandP.40).аспн

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

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

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

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

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

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

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

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

еще одна проблема с 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 свойства может измениться".

просто использовать INotifyPropertyChange в вашем viewmodel, а не в модели,

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

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

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

хотя его до вас, чтобы решить, хотите ли вы этот тип реализации или нет, но помните -

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

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

принято от - http://msdn.microsoft.com/en-us/library/gg405484(PandP.40).аспн

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

вы столкнетесь с проблемами, особенно если вам нужно работать с коллекцией ваших объектов модели (скажем, в редактируемой сетке или списке) или сложных моделей; объекты модели не будут обновляться автоматически, и вам придется управлять всем этим в вашем ВИРТУАЛЬНАЯ ПАМЯТЬ.


первоначально ответил на другой подобный вопрос, добавив сюда, поскольку он содержит imp. детали отсутствуют в этой теме -

https://stackoverflow.com/a/6923833/45382

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

так что я делаю, чтобы позволить самому объекту уведомлять кого-либо, когда значение в свойстве изменяется, и, на мой взгляд, я использую привязки, такие как Object.Property1,Object.Property2 и далее. Таким образом, если я просто хочу изменить объект, который в настоящее время поддерживается на мой взгляд, я просто делаю OnPropertyChanged("Object").

чтобы избежать сотен уведомлений во время загрузки объектов, у меня есть частный логический индикатор, который я установил в true во время загрузки, который проверяется из объекта OnPropertyChanged и ничего не делает.

Я использую INotifyPropertyChange интерфейс в модели. На самом деле, изменение свойства модели должно быть запущено только пользовательским интерфейсом или внешним клиентом.

Я заметил несколько преимуществ и недостатков:

преимущества

Notifier находится в бизнес-модели

  1. согласно управляемому домену, оно прав. Он должен решить, когда поднимать, а когда нет.

недостатки

в модель имеет свойства (кол-во, ставка, комиссия, totalfrieght). Totalfrieght рассчитывается с использованием кол-во, ставки, изменения комиссии.

  1. при загрузке значений из БД, расчет общего frieght называется 3 раза (кол-во, ставка, комиссии). Это должно быть один раз.

  2. Если rate, qty назначается на бизнес-уровне, снова вызывается notifier.

  3. там должна быть возможность отключить это, возможно в базовом классе. Однако, разработчики могли забыть это сделать.

обычно ViewModel реализует INotifyPropertyChanged. Модель может быть любой(xml-файл, база данных или даже объект). Модель используется для передачи данных в viewmodel, который распространяется на представление.

посмотреть здесь

имхо я думаю, что viewmodel реализует INotifyPropertyChange и эта модель может использовать уведомление на другом "уровне".

например с некоторой службой документов и объектом документа у вас есть событие documentChanged, которое прослушивает viewmodel, чтобы очистить и перестроить представление. В edit viewmodel у вас есть propertychange для свойств документа для поддержки представлений. Если сервис много делает с документом на сохранение (обновление даты изменения, последнего пользователя и так далее) вы легко получаете достаточно перегрузки Ipropertychanged событий и просто documentchanged.

но если вы используете INotifyPropertyChange в вашей модели я думаю, что это хорошая практика, чтобы передать его в вашем viewmodel вместо подписки на него непосредственно в вашем представлении. В том случае, когда изменения в модели, вам нужно только изменить ViewModel и вид останется нетронутым.