Question MVVM - PropertyChanged dans Model ou ViewModel?


Je suis passé par quelques tutoriels MVVM et j'ai vu cela se faire dans les deux sens. La plupart utilisent le ViewModel pour PropertyChanged (ce que je faisais), mais j'en ai rencontré un dans le modèle. Les deux méthodes sont-elles acceptables? Si oui, quels sont les avantages / inconvénients des différentes méthodes?


17
2018-05-31 19:34


origine


Réponses:


le INotifyPropertyChanged (INPC) interface est utilisée pour Binding.

Donc, dans le cas moyen, vous voulez l'implémenter dans votre ViewModel.

le ViewModel est utilisé pour découpler le Model de ton View, donc il n'y a pas besoin d'avoir INPC dans votre Modelcomme vous ne voulez pas Bindings à ton Model.

Dans la plupart des cas, même pour les petites propriétés, vous avez toujours un très petit ViewModel.

Si vous voulez une base solide pour MVVM, vous allez probablement utiliser une sorte de Framework MVVM comme calibr.micro. L’utiliser vous donnera un ViewModelBase (ou ici NotifyPropertyChangedBase) de sorte que vous ne devez pas implémenter ces membres d'interface vous-même et pouvez simplement utiliser NotifyOfPropertyChange(() => MyProperty), ce qui est beaucoup plus facile et moins sujet aux erreurs.

METTRE À JOUR Comme il semble y avoir beaucoup de développeurs Windows Forms, voici un excellent article qui permettra de mieux comprendre ce qu'est le MVVM: MSDN Magazine sur MVVM

J'ai lié en particulier la partie sur le modèle de données dont il est question.


15
2018-05-31 19:39



Microsoft Patterns and Practices, l'inventeur du MVVM, et je ne suis pas du tout d'accord avec la réponse choisie.

En règle générale, le modèle implémente les fonctionnalités qui facilitent la liaison à la vue. Cela signifie généralement qu'il prend en charge les notifications de propriété et de collection modifiées via les interfaces INotifyPropertyChanged et INotifyCollectionChanged. Les classes de modèles qui représentent des collections d'objets dérivent généralement de la classe ObservableCollection, qui fournit une implémentation de l'interface INotifyCollectionChanged.

- Modèles Microsoft et pratiques: http://msdn.microsoft.com/en-us/library/gg405484%28v=pandp.40%29.aspx#sec4

À ce stade, la liaison de données entre en jeu. Dans des exemples simples, la vue est une donnée directement liée au modèle. Des parties du modèle sont simplement affichées dans la vue par une liaison de données unidirectionnelle. D'autres parties du modèle peuvent être éditées en liant directement les contrôles dans les deux sens aux données. Par exemple, un booléen dans le modèle peut être une donnée liée à une case à cocher ou une chaîne à une zone de texte.

- John Gossman, inventeur du MVVM: http://blogs.msdn.com/b/johngossman/archive/2005/10/08/478683.aspx

Mon propre article: http://www.infoq.com/articles/View-Model-Definition


C'est un anti-pattern d'avoir un "modèle de vue" qui encapsule un modèle et expose la même liste de propriétés. Le travail du modèle de vue consiste à appeler des services externes et à exposer l'individu et les collections de modèles renvoyés par ces services.

Les raisons:

  1. Si le modèle est mis à jour directement, le modèle de vue ne saura pas déclencher un événement de modification de propriété. Cela provoque la désynchronisation de l'interface utilisateur.
  2. Cela limite considérablement vos options d'envoi de messages entre les modèles de vue parent et enfant.
  3. Si le modèle a sa propre propriété, la notification de modification, # 1 et 2 ne sont pas un problème. Au lieu de cela, vous devez vous soucier des fuites de mémoire si la machine virtuelle wrapper est hors de portée, mais pas le modèle.
  4. Si vos modèles sont complexes, avec beaucoup d’objets enfants, vous devez parcourir l’arbre entier et créer un second graphe d’objet qui masque le premier. Cela peut être très fastidieux et sujet aux erreurs.
  5. Les collections emballées sont particulièrement difficiles à utiliser. Chaque fois que quelque chose (interface utilisateur ou backend) insère ou supprime un élément d'une collection, la collection d'ombres doit être mise à jour pour correspondre. Ce type de code est vraiment difficile à obtenir.

Cela ne veut pas dire que vous n'aurez jamais besoin d'un modèle de vue qui enveloppe un modèle. Si votre modèle de vue expose des propriétés significativement différentes du modèle et qu'il ne suffit pas de les écraser avec un IValueConverter, un modèle de vue enveloppant prend tout son sens.

Une autre raison pour laquelle vous pouvez avoir besoin d'un modèle de vue d'encapsulation est que vos classes de données ne prennent pas en charge la liaison de données pour une raison quelconque. Mais même dans ce cas, il est généralement préférable de créer un modèle normal et pouvant être lié et de copier les données des classes de données d'origine.

Et bien sûr, votre modèle de vue aura des propriétés spécifiques à l'interface utilisateur, telles que l'élément actuellement sélectionné dans une collection.


27
2018-05-31 20:45



Serait absolument d'accord avec Jonathan Allen.

Si vous n’avez rien à ajouter à votre «modèle de vue» (commandes, propriétés spécifiques à la vue qui affectent la présentation, etc.), alors je voudrais implémenter INotifyPropertyChanged dans le modèle et exposer cela directement (si vous le pouvez, le soyez à vous). Non seulement vous vous retrouvez à répéter beaucoup de code standard, mais garder les deux synchrones est une douleur absolue.

INotifyPropertyChanged n'est pas une interface spécifique à une vue, elle fait exactement ce que son nom suggère - déclenche un événement lorsqu'une propriété change. WinForms, WPF et Silverlight le supportent pour Binding - je l'ai certainement utilisé à des fins non-présentationnelles!


4
2018-06-03 18:12



En règle générale, tout objet auquel vous vous liez (même si vous n'avez pas besoin d'une liaison bidirectionnelle et de notification de modification de propriété) doit implémenter INotifyPropertyChanged. C'est parce que ne pas le faire Peut provoquer des fuites de mémoire


1
2018-05-31 19:37



INotifyPropertyChanged doit être implémenté par tous les types consommés par la vue (sauf si elle ne contient que des valeurs constantes).

Est-ce que vous renvoyez des modèles (pas des modèles de vue) à une vue? Si oui, alors il devrait implémenter INotifyPropertyChanged.


1
2018-05-31 19:39



Bien que je sois généralement favorable à un modèle implémentant INPC, l'appel à INPC dans un modèle de vue composite se produit lorsqu'il expose des propriétés inférées pouvant être liées à la vue. OMI puisque INPC est cuit dans System.dll, un modèle l'implémentant peut être considéré comme POCO. Pour les collections, il y a un avantage de performance de l'INPC basé sur le modèle. Sur une plate-forme 64 bits, une machine virtuelle encapsuleuse aurait un multiplicateur de 8 facteurs sur la taille en octets (chargez l'extension de débogueur SOS pour la taille réelle) de ObservableCollection <ViewModel> par rapport à ObservableCollection <Model>.


1
2017-07-24 13:53



Le créateur de MVVM, JohnGossman, déclare dans ce article de blog (mentionné par @Jonathan Allen) qui:

Dans des exemples simples, la vue est une donnée directement liée au modèle.   Des parties du modèle sont simplement affichées dans la vue par des données à sens unique   contraignant. D'autres parties du modèle peuvent être éditées en liant directement   contrôle bidirectionnel vers les données. Par exemple, un booléen dans le modèle peut   être des données liées à un CheckBox ou un champ de chaîne à une zone de texte.

En pratique, toutefois, seule une petite partie de l’interface utilisateur de l’application peut être une donnée.   lié directement au modèle, surtout si le modèle est un modèle préexistant   classe ou schéma de données sur lequel le développeur de l'application n'a pas   contrôle.   

Je préfère suivre les pratiques toujours applicables lorsque l'application évolue. Si "En pratique [...], seul un petit sous-ensemble de l'interface utilisateur de l'application peut être lié directement au modèle", cela ne semble pas être une bonne pratique à suivre car je ne prévois pas seulement "simple cases "ou" un petit sous-ensemble de l'interface utilisateur de l'application ".
Pour les "cas simples", je n'utiliserais même pas MVVM pour commencer.


1
2017-07-13 21:23