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

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

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

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

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

15 ответов


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

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


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

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

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

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

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


в 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 полезна для пользовательского интерфейса, но не обязательно только для UI. Это для бизнес-слоя, UI-слоя и т. д...

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

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


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

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

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


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

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

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

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


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


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


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

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

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

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

еще одна проблема с 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? Что некоторые его свойства могут измениться. Ты не знаешь, кто из них. На самом деле дизайн заключается в том, что только связанные изменения, так как остальные из них доступны только для чтения.

напротив, намерения 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).aspx

я работал в некоторых проектах, где мы не выполнили 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. при загрузке значений из БД, общий расчет испуга вызывается 3 раза (кол-во, ставка, комиссия). Это должно быть один раз.

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

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


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

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


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

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

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