Lors de l’implémentation de ViewModel dans une application WPF d’architecture Model-View-ViewModel, il semble y avoir deux choix majeurs pour le rendre databindable. J’ai vu des implémentations qui utilisent DependencyProperty
pour les propriétés sur lesquelles View va se lier et j’ai vu le ViewModel implémentant INotifyPropertyChanged
place.
Ma question est: quand devrais-je préférer l’un à l’autre? Y a-t-il des différences de performance? 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?
Kent a écrit un blog intéressant sur ce sujet: View Models: POCOs versus DependencyObjects .
Court résumé:
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
Selon le guide de performances WPF, DependencyObjects est nettement plus performant que les POCO qui implémentent INotifyPropertyChanged:
Le choix est totalement basé sur votre logique métier et le niveau d’abstraction de l’interface utilisateur. Si vous ne voulez pas une bonne séparation, DP travaillera pour vous.
DependencyProperties sera principalement applicable au niveau de VisualElements, il ne sera donc pas judicieux de créer de nombreux PD pour chacun de nos besoins métier. Il y a aussi un coût plus élevé pour DP qu’un INotifyPropertyChanged. Lorsque vous concevez un WPF / Silverlight, essayez de concevoir une interface utilisateur et ViewModel totalement séparés de manière à pouvoir modifier à tout moment les contrôles Layout et UI (en fonction du thème et des styles)
Reportez-vous également à cet article – 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, ce qui est très pertinent pour cette discussion.
Du sharepoint vue de l’expressivité, j’apprécie INotifyPropertyChanged
utilisation des propriétés de dépendance et le fait de penser à INotifyPropertyChanged
. Outre les noms de propriétés de ssortingng
et les éventuelles memory leaks 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” en utilisant des métadonnées statiques faciles à comprendre. C’est une approche déclarative qui me permet de voter pour l’élégance.
INotifyPropertyChanged
lorsqu’il est utilisé vous donne également la possibilité d’append plus de logique dans le code de vos getters et de votre setter de vos propriétés.
Exemple de DependencyProperty
:
public static DependencyProperty NameProperty = DependencyProperty.Register( "Name", typeof( Ssortingng), typeof( Customer ) ); public Ssortingng Name { set { SetValue( NameProperty, value ); } get { return ( Ssortingng ) GetValue( NameProperty ); } }
Dans votre getter et setter — tout ce que vous pouvez faire est d’appeler SetValue et GetValue respectivement, b / c dans d’autres parties du framework, le getter / setter n’est pas appelé, au lieu de cela, il appelle directement SetValue, GetValue. être exécuté de manière fiable.
Avec INotifyPropertyChanged
, définissez un événement:
public event PropertyChangedEventHandler PropertyChanged;
Et puis, il suffit d’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 ailleurs.
Les propriétés de dépendance sont conçues pour prendre en charge la liaison (en tant que cible) sur les éléments de l’interface utilisateur et non comme une source de liaison de données. C’est là qu’intervient INotifyProperty. Vous ne devez pas utiliser DP sur 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 en tant que source de liaison. Toutefois, pour être la cible d’une liaison, la propriété doit être une propriété de dépendance: pour qu’une liaison unidirectionnelle ou bidirectionnelle soit effective, 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, la propriété doit prendre en charge INotifyPropertyChanged. Les collections doivent supporter INotifyCollectionChanged. ”
Tous les objects 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 dans 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
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 à une structure de logique métier existante sans dupliquer l’état. Le cadre que j’utilisais avait son propre modèle d’observateur et il était facile de transmettre un niveau de notification au suivant. J’avais simplement une classe qui implémentait l’interface de l’observateur à partir de mon framework de logique métier et de l’interface INotifyPropertyChanged.
Avec DP, vous ne pouvez pas définir le backend qui stocke vous-même l’état. 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 vaste et compliqué.
Donc, ici, j’ai trouvé INotifyPropertyChanged mieux pour exposer les propriétés de la logique métier à l’interface graphique.
Cela étant dit, lorsque j’avais besoin d’un widget d’interface graphique personnalisé pour exposer une propriété et que les modifications apscopes à cette propriété affectaient d’autres widgets d’interface graphique, DP s’est avéré la solution simple.
Donc là, j’ai trouvé DP utile pour l’interface graphique à la notification GUI.
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’un framework arbitraire pour l’utiliser. Voir l’article de Rob Relyea sur sa session PDC.
Ma prise
XAML est un langage de description d’objects et WPF est un framework dont les objects décrits sont des éléments d’interface utilisateur.
Leur relation est similaire à C #, un langage de description de logique, et .NET, un framework qui implémente des types de logique particuliers.
Le but de XAML est les graphes d’object déclaratifs. Les technologies W * F sont d’excellents candidats pour ce paradigme, mais XAML existe indépendamment d’eux.
XAML et l’ensemble du système de dépendance ont été implémentés en tant que stacks 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) entre elles.
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 dans XAML et utiliser toutes les fonctionnalités WPF, ces propriétés doivent posséder des propriétés de dépendance.
Cependant, votre ViewModel utilise mieux INotifyPropertyChanged. Utiliser INotifyPropertyChanged vous donnera la possibilité d’avoir une logique getter / setter si nécessaire.
Je recommande de vérifier 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 c’est un excellent exemple de la façon de faire un ViewModel.
Je pense que DependencyProperty et INotifyPropertyChanged sont utilisés pour deux choses différentes dans la liaison: la première pour permettre à une propriété d’être la cible d’une liaison et de recevoir l’entrée d’une autre propriété (utilisez {Binding …} pour définir la propriété). 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). Le choix est donc simplement technique.
Les propriétés de dépendance sont le ciment de la création d’un contrôle personnalisé. Si vous souhaitez utiliser Intelli-sense pour afficher vos propriétés dans la fenêtre des propriétés au moment du design XAML, vous devez utiliser les propriétés de dépendance. INPC ne montrera jamais une propriété dans la fenêtre de propriété au moment du design.
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 vous connecter directement aux propriétés CLR sans code de comptabilité. Vous écrivez simplement du code .NET dans votre modèle de vue et celui-ci est mis à jour lorsque votre modèle de données change.
Il n’y a qu’une seule chose pour laquelle préférer un DependencyObject
– la liaison fonctionnera mieux. Essayez simplement un exemple avec ListBox
et TextBox
, INotifyPropertyChanged
liste avec les données de la propriété INotifyPropertyChanged
rapport à DependencyProperty
et modifiez l’élément actuel à partir de TextBox
…
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 elles prennent un certain temps à comprendre …