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

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

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

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

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

16 ответов

Решение

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

/questions/2753888/v-modeli-mvvm-model-dolzhna-realizovyivat-interfejs-inotifypropertychanged/2753918#2753918

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

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

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

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

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

Мне кажется, ответ вполне понятен, если вы хотите придерживаться MV-VM.

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

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

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

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

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

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

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

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

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

Уведомитель в бизнес-модели

  1. Что касается домена, это правильно. Следует решить, когда повышать, а когда нет.

Недостатки

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

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

  2. Если в бизнес-уровне назначена скорость, кол-во, снова вызывается уведомитель.

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

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

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

Все свойства, которые связаны с моим представлением, находятся в моих ViewModel(s). Таким образом, они должны реализовать интерфейс INotifyPropertyChanged. Поэтому View получает все изменения.

[Используя инструментарий MVVM Light, я позволил им наследовать от ViewModelBase.]

Модель содержит бизнес-логику, но не имеет ничего общего с представлением. Таким образом, нет необходимости в интерфейсе INotifyPropertyChanged.

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

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

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

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

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

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

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

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

Другие вопросы по тегам