INotifyPropertyChanged или DependencyProperty в ViewModel

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

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

Ответ 1

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

Краткое описание:

  • DependencyObjects не помечены как сериализуемый
  • Класс DependencyObject переопределяет и уплотняет Equals() и Методы GetHashCode()
  • A DependencyObject имеет сходство потоков - к нему можно получить доступ только на нитке, на которой она была создано

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

Ответ 2

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

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

Ответ 3

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

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

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

Ответ 4

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

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

Ответ 5

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 ); }
}

В вашем getter и setter --- все, что вы можете сделать, это просто вызвать SetValue и GetValue соответственно, b/c в других частях фрейма, которые не вызывают getter/setter, вместо этого он напрямую вызывает 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...

Это может быть в getter/setter или где-либо еще.

Ответ 6

Свойства зависимостей предназначены для поддержки привязки (как цели) к элементам пользовательского интерфейса, а не как источника привязки данных, здесь используется 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

Ответ 7

Мне тоже пришлось рассмотреть это решение недавно.

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

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

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

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

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

Ответ 8

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

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

Мой прием

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

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

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

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

Ответ 9

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

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

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

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

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

Ответ 10

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

Ответ 11

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

Ответ 12

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

Ответ 13

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

Ответ 14

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