web-dev-qa-db-fra.com

INotifyPropertyChanged vs DependencyProperty dans ViewModel

Lors de l'implémentation du ViewModel dans une application WPF à architecture Modèle-View-ViewModel, il semble y avoir deux choix majeurs: comment le rendre databindable. J'ai vu des implémentations qui utilisent DependencyProperty pour les propriétés que la vue va lier et j'ai vu le ViewModel implémenter INotifyPropertyChanged à la place.

Ma question est de savoir quand devrais-je préférer l'un à l'autre? Existe-t-il des différences de performances? Est-ce vraiment une bonne idée de donner les dépendances ViewModel à WPF? Que dois-je considérer d'autre pour prendre la décision de conception?

347
bitbonk

Kent a écrit un blog intéressant sur ce sujet: View Models: POCOs versus DependencyObjects .

Résumé succinct:

  1. Les DependencyObjects ne sont pas marqués comme sérialisables
  2. La classe DependencyObject annule et scelle les méthodes Equals () et GetHashCode ()
  3. Un DependencyObject a une affinité de thread - il ne peut être consulté que sur le thread sur lequel il a été créé

Je préfère l'approche POCO. Une classe de base pour PresentationModel (aka ViewModel) qui implémente l'interface INotifyPropertyChanged peut être trouvée ici: http://compositeextensions.codeplex.com

210
jbe

Selon le guide de performances WPF, les objets DependencyObjects fonctionnent nettement mieux que les objets POCO implémentant INotifyPropertyChanged:

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

37
James Ashley

Le choix est totalement basé sur votre logique métier et votre niveau d'abstraction de l'interface utilisateur. Si vous ne voulez pas une bonne séparation, DP travaillera pour vous.

DependencyProperties s’appliquera principalement au niveau VisualElements. Il ne serait donc pas judicieux de créer un grand nombre de PDD pour chacune de nos exigences métier. De plus, le coût pour DP est supérieur à celui d'un INotifyPropertyChanged. Lorsque vous concevez un WPF/Silverlight, essayez de concevoir l'interface utilisateur et ViewModel de manière totalement distincte, de sorte que vous puissiez à tout moment modifier les contrôles de présentation et d'interface utilisateur (en fonction du thème et des styles).

Référez-vous également à ce message - https://stackoverflow.com/questions/275098/what-applications-could-i-study-to-understand-datamodel-view-viewmodel . Le lien fait beaucoup référence au modèle Model-View-ViewModel, qui est très pertinent pour cette discussion.

27
Jobi Joy

D'un point de vue expressif, j'apprécie énormément l'utilisation des propriétés de dépendance et évite de penser à INotifyPropertyChanged. Outre les noms de propriété string et les éventuelles fuites de mémoire dues à l'abonnement aux événements, INotifyPropertyChanged est un mécanisme beaucoup plus explicite.

Les propriétés de dépendance impliquent "quand cela, fait cela" en utilisant des métadonnées statiques faciles à comprendre. C'est une approche déclarative qui obtient mon vote pour l'élégance.

19
Bryan Watts

Les propriétés de dépendance sont conçues pour prendre en charge la liaison (en tant que cible) sur des éléments d'interface utilisateur, et non en tant que liaison entre la source et les données. C'est ici qu'InotifyProperty entre en jeu. D'un point de vue pur, vous ne devez pas utiliser DP sur un ViewModels.

"Pour être la source d'une liaison, une propriété ne doit pas nécessairement être une propriété de dépendance; vous pouvez utiliser n'importe quelle propriété CLR comme source de liaison. Toutefois, pour être la cible d'une liaison, elle doit être une Dépendance Pour qu'une liaison unidirectionnelle ou bidirectionnelle soit efficace, la propriété source doit prendre en charge les notifications de modification qui se propagent au système de liaison et donc à la cible. Pour les sources de liaison CLR personnalisées, cela signifie que la propriété doit prendre en charge INotifyPropertyChanged. Les collections doivent prendre en charge INotifyCollectionChanged. "

Tous les objets de dépendance ne peuvent pas être sérialisés (cela pourrait entraver l'utilisation de ViewModels et de DTO (POCO).

Il existe des différences entre DP au sein de Silverlight et WPF.

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

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

16
Nick Hermans

INotifyPropertyChanged lorsqu’il est utilisé vous donne également la possibilité d’ajouter plus de logique dans le code de vos accesseurs et dans celui de vos propriétés.

DependencyProperty exemple:

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

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

Dans votre getter et votre setter - tout ce que vous pouvez faire est simplement d'appeler SetValue et GetValue respectivement, b/c dans d'autres parties du cadre, le getter/setter n'est pas appelé, mais à la place, il appelle directement SetValue, GetValue, afin que votre logique de propriété ne être exécuté de manière fiable.

Avec INotifyPropertyChanged, définissez un événement:

public event PropertyChangedEventHandler PropertyChanged;

Et puis simplement avoir n'importe quelle logique n'importe où dans votre code, puis appelez:

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

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

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

Cela pourrait être dans un getter/setter, ou n'importe où ailleurs.

16
Adam

Moi aussi j'ai dû prendre en compte cette décision récemment.

J'ai constaté que le mécanisme INotifyPropertyChanged répondait mieux à mes besoins, car il me permettait de coller mon interface graphique à un cadre de logique métier existant sans dupliquer l'état. Le cadre que j'utilisais avait son propre modèle d'observateur et il était facile de transférer un niveau de notification à un autre. J'avais simplement une classe qui implémentait l'interface observateur à partir de mon cadre de logique métier et de l'interface INotifyPropertyChanged.

Avec DP, vous ne pouvez pas définir le backend qui stocke l’état vous-même. J'aurais dû laisser .net mettre en cache une copie de chaque élément d'état auquel j'étais lié. Cela semblait être une surcharge inutile - mon état est grand et compliqué.

J'ai donc trouvé INotifyPropertyChanged mieux pour exposer les propriétés de la logique métier à l'interface graphique.

Cela dit, il me fallait un widget d'interface graphique personnalisé pour exposer une propriété et pour que les modifications apportées à cette propriété affectent d'autres widgets d'interface graphique. DP était la solution simple.

J'ai donc trouvé que DP était utile pour les notifications d'interface graphique à interface graphique.

7
morechilli

Est-ce vraiment une bonne idée de donner les dépendances ViewModel à WPF?

.NET 4.0 aura System.Xaml.dll, vous n’aurez donc pas à dépendre d’une infrastructure arbitraire pour l’utiliser. Voir Rob Relyea poste sur sa PDC session.

Ma prise de vue

XAML est un langage de description d'objets et WPF est un framework dont les objets décrits sont des éléments d'interface utilisateur.

Leur relation est similaire à C #, un langage de description de la logique, et à .NET, un framework qui implémente des types de logique particuliers.

L'objectif de XAML est les graphes d'objets déclaratifs. Les technologies W * F sont d'excellents candidats pour ce paradigme, mais le XAML existe indépendamment d'eux.

XAML et l'ensemble du système de dépendance ont été mis en œuvre sous forme de piles séparées pour WF et WPF), probablement pour tirer parti de l'expérience de différentes équipes sans créer de dépendance (sans jeu de mots).

6
Bryan Watts

Les propriétés de dépendance sont le ciment de la création de contrôles personnalisés. Si vous souhaitez utiliser Intelli-sense pour afficher vos propriétés dans la fenêtre des propriétés au moment de la conception XAML, vous devez utiliser les propriétés de dépendance. INPC n’affiche jamais une propriété dans la fenêtre de la propriété au moment de la conception.

5
John Peters

Il semble que les propriétés de dépendance doivent être utilisées dans les contrôles que vous créez, tels que les boutons. Pour utiliser les propriétés en XAML et utiliser toutes les fonctionnalités de WPF, ces propriétés doivent être Propriétés de dépendance.

Cependant, votre ViewModel est préférable d'utiliser INotifyPropertyChanged. L'utilisation de INotifyPropertyChanged vous donnera la possibilité d'avoir une logique getter/setter si vous en avez besoin.

Je recommande de consulter la version de Josh Smith d'une classe de base pour un ViewModel qui implémente déjà INotifyPropertyChanged:

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

Je pense que ceci est un excellent exemple de la façon de faire un ViewModel.

4
timothymcgrath

Je pense que DependencyProperty et INotifyPropertyChanged sont utilisés dans Binding pour deux choses différentes: la première pour permettre à une propriété de devenir la cible d’une liaison et de recevoir l’entrée d’une autre propriété (utilisez {Binding ...} pour définir la propriété), la dernière. lorsque vous souhaitez que la valeur d'une propriété soit utilisée comme source d'une liaison (nom dans l'expression du chemin de liaison). Donc, le choix est simplement technique.

4
Domnik

Pourquoi préférer un DependencyObject? La liaison fonctionnera mieux. Essayez juste un exemple avec ListBox et TextBox, remplissez la liste avec les données de la propriété INotifyPropertyChanged contre DependencyProperty et modifiez l’élément en cours à partir de TextBox...

3
ramos

Je préfère une approche plus directe, sur laquelle j'ai blogué dans Presentation Model Without INotifyPropertyChanged . En utilisant une alternative à la liaison de données, vous pouvez lier directement aux propriétés du CLR sans code de comptabilité. Vous venez d'écrire du code .NET pur et ancien dans votre modèle de vue, qui est mis à jour lorsque votre modèle de données change.

3
Michael L Perry

Si vous souhaitez exposer des propriétés à d'autres contrôles, vous devez utiliser les propriétés de dépendance ... Mais bonne chance, car il leur faut un certain temps pour comprendre ...

1
JWP