INotifyPropertyChanged против DependencyProperty в ViewModel

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

мой вопрос в том, когда я должен предпочесть один над другим? Есть ли различия в производительности? Действительно ли это хорошая идея, чтобы дать зависимости ViewModel В WPF? Что еще мне нужно учитывать при принятии проектного решения?

14 ответов


Кент написал интересный блог на эту тему:просмотр моделей: POCOs против DependencyObjects.

краткий итог:

  1. DependencyObjects не помечены как serializable
  2. класс DependencyObject переопределяет и запечатывает Equals () и Метод GetHashCode() методы
  3. DependencyObject имеет сродство потоков – он может быть доступен только на нити, на которой он был создано

I предпочитаю подход POCO. Базовый класс для PresentationModel (он же ViewModel), который реализует интерфейс INotifyPropertyChanged, можно найти здесь:http://compositeextensions.codeplex.com


согласно Руководству по производительности WPF, DependencyObjects определенно работают лучше, чем POCOs, которые реализуют INotifyPropertyChanged:

http://msdn.microsoft.com/en-us/library/bb613546.aspx


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

DependencyProperties будут применимы главным образом на уровне VisualElements поэтому не будет хорошей идеей если мы создадим серию DPs для каждого из наших требований к дела. Также существует большая стоимость для DP, чем INotifyPropertyChanged. Когда вы разрабатываете WPF / Silverlight, попробуйте создать UI и ViewModel полностью отдельно, чтобы в любой момент времени мы можем изменить макет и элементы управления UI (на основе темы и стилей)

см. этот пост также - https://stackoverflow.com/questions/275098/what-applications-could-i-study-to-understand-datamodel-view-viewmodel . Ссылка имеет много ссылок на шаблон Model-View-ViewModel, который очень актуален для этого обсуждения.


С точки зрения выразительности я полностью наслаждаюсь использованием свойств зависимости и съеживаюсь при мысли о INotifyPropertyChanged. Кроме string имена свойств и возможных утечек памяти из-за подписки на события INotifyPropertyChanged является гораздо более явным механизмом.

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


INotifyPropertyChanged при использовании дает вам возможность добавить больше логики в код геттеров и сеттеров свои свойства.

DependencyProperty пример:

public static DependencyProperty NameProperty = DependencyProperty.Register( "Name", typeof( String), typeof( Customer ) );

public String Name
{
    set { SetValue( NameProperty, value ); }
    get { return ( String ) GetValue( NameProperty ); }
}

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

С INotifyPropertyChanged, определить событие:

public event PropertyChangedEventHandler PropertyChanged;

а затем просто иметь любую логику в любом месте вашего кода, а затем позвонить:

// ...
// Something cool...
// ...

if( this.PropertyChanged != null )
{
    PropertyChanged( this, new PropertyChangedEventArgs( "Name" ) );
}

// More cool stuff that will reliably happen...

это может быть в геттер/сеттер, или где-нибудь еще.


свойства зависимостей предназначены для поддержки привязки (в качестве цели) на элементах пользовательского интерфейса, а не в качестве источника привязки данных, здесь входит INotifyProperty. С чистой точки зрения вы не должны использовать DP на ViewModels.

" чтобы быть источником привязки, свойство не должно быть свойством зависимости; вы можете использовать любое свойство CLR в качестве источника привязки. Однако, для того, чтобы быть целью привязки, свойство должно быть свойством зависимостей. Для односторонняя или двусторонняя привязка чтобы быть эффективной, свойство source должно поддерживать уведомления об изменениях, которые распространяются на систему привязки и, следовательно, цель. Для пользовательских источников привязки среды CLR это означает, что свойство должно поддерживать INotifyPropertyChanged. Коллекции должны поддерживать INotifyCollectionChanged."

все объекты зависимостей не могут быть сериализованы (это может помешать использованию ViewModels и DTO (POCO).

существуют различия между DP в Silverlight по сравнению с WPF.

http://msdn.microsoft.com/en-us/library/cc221408 (v=VS.95).aspx

http://msdn.microsoft.com/en-us/library/cc903933 (VS.95).aspx


Я тоже должен был рассмотреть это решение в последнее время.

Я обнаружил, что механизм INotifyPropertyChanged лучше подходит для моих потребностей, потому что он позволяет мне приклеить мой GUI к существующей структуре бизнес-логики без дублирования состояния. Структура, которую я использовал, имела свой собственный шаблон наблюдателя, и было легко переслать один уровень уведомления на следующий. У меня просто был класс, который реализовал интерфейс observer из моей структуры бизнес-логики и Интерфейс INotifyPropertyChanged.

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

Итак, здесь я нашел INotifyPropertyChanged лучше для отображения свойств из бизнес-логики в GUI.

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

Итак, я нашел DP полезным для GUI для уведомления GUI.


действительно ли хорошая идея дать зависимости ViewModel для WPF?

.NET 4.0 будет иметь систему.код XAML.dll, поэтому вам не придется принимать зависимость от произвольной структуры, чтобы использовать ее. См.Роб компакт-диск рели сообщение о его сеансе PDC.

мое мнение

XAML-это язык для описания объектов, а WPF-это платформа, описываемые объекты которой являются элементами пользовательского интерфейса.

их отношения подобно C#, язык для описания логики и .NET, платформа, которая реализует определенные виды логики.

цель XAML-декларативные графы объектов. Технологии W*F являются отличными кандидатами на эту парадигму, но XAML существует независимо от них.

XAML и вся система зависимостей были реализованы как отдельные стеки для WF и WPF, вероятно, для использования опыта разных команд без создания зависимости (без каламбура) между их.


кажется, что свойства зависимостей должны использоваться в элементах управления, которые вы создаете, такие как кнопки. Чтобы использовать свойства в XAML и использовать все функции WPF, эти свойства должны иметь свойства зависимостей.

однако вашей ViewModel лучше использовать INotifyPropertyChanged. Использование INotifyPropertyChanged даст вам возможность иметь логику геттера/сеттера, если вам нужно.

Я рекомендую проверить версию базового класса Джоша Смита для ViewModel, которая уже реализует INotifyPropertyChanged в:

http://joshsmithonwpf.wordpress.com/2007/08/29/a-base-class-which-implements-inotifypropertychanged/

Я думаю, что это отличный пример того, как сделать ViewModel.


Я думаю, что DependencyProperty и INotifyPropertyChanged используются для двух разных вещей в привязке : первый для включения свойства в качестве цели привязки и получения входных данных от другого свойства (используйте {Binding ...} чтобы задать свойство), последнее, когда вы хотите, чтобы значение свойства использовалось в качестве источника привязки (имя в выражении пути привязки). Так что выбор чисто технический.


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


Я предпочитаю более прямой подход, о котором я написал в блоге в Модель Представления Без INotifyPropertyChanged. Используя альтернативу привязке данных, можно привязать непосредственно к свойствам CLR без какого-либо кода бухгалтерского учета. Вы просто пишете простой код .NET в своей модели представления, и он обновляется при изменении модели данных.


есть только одна вещь, почему предпочитают DependencyObject - привязка будет работать лучше. Просто попробуйте пример с ListBox и TextBox, заполнить список данными из INotifyPropertyChanged или DependencyProperty и редактировать текущий элемент из TextBox...


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