Dans MVVM, le ViewModel ou le modèle devrait-il implémenter INotifyPropertyChanged?
La plupart des exemples MVVM que j'ai traités ont eu le modèle implémenter INotifyPropertyChanged, mais dans l'exemple CommandSink de Josh Smith le ViewModel implémente INotifyPropertyChanged .
Je suis toujours en train de rassembler les concepts MVVM, donc je ne sais pas si:
- Vous devez mettre le INotifyPropertyChanged dans le ViewModel pour que CommandSink fonctionne
- c'est juste une aberration de la norme et ce n'est pas vraiment le cas matière
- Vous devriez toujours avoir le modèle implémenter INotifyPropertyChanged et ceci est juste une erreur qui serait corrigée si cela était développé à partir d'un exemple de code à une application
Quelles ont été les expériences des autres sur les projets MVVM sur lesquels vous avez travaillé?
15 réponses
Je dirais tout le contraire, je mets toujours mon INotifyPropertyChanged
sur mon ViewModel - vous ne voulez vraiment pas polluer votre modèle avec une fonctionnalité assez spécifique à WPF comme INotifyPropertyChanged
, ce truc devrait rester dans le ViewModel.
Je suis sûr que les autres ne seraient pas d'accord, mais c'est comme ça que je travaille.
Je suis fortement en désaccord avec le concept selon lequel le modèle ne devrait pas implémenter le INotifyPropertyChanged
. Cette interface N'est pas spécifique à L'interface utilisateur! Il informe simplement d'un changement. En effet, WPF l'utilise fortement pour identifier les changements, mais cela ne signifie pas qu'il s'agit d'une interface utilisateur.
Je le comparerais le commentaire suivant: "un pneu est Un accessoire de voiture". Bien sûr, mais les vélos, les bus, etc. également l'utiliser. en résumé, ne prenez pas cette interface comme une chose de L'interface utilisateur.
Cela dit, ce n'est pas le cas nécessairement dire que je crois que le modèle devrait fournir des notifications. En fait, en règle générale, le modèle ne doit pas implémenter cette interface, sauf si cela est nécessaire. dans la plupart des cas où aucune donnée du serveur n'est transmise à l'application cliente, le modèle peut être périmé. Mais si vous écoutez les données du marché financier, alors je ne vois pas pourquoi le modèle ne peut pas implémenter l'interface. À titre d'exemple, que se passe-t-il si j'ai une logique non-UI telle qu'un service qui reçoit un prix acheteur ou vendeur pour un prix donné valeur il émet une alerte (ex. par e-mail) ou passe une commande? Ce pourrait être une solution propre.
Cependant, il y a différentes façons de réaliser les choses, mais je plaiderais toujours en faveur de la simplicité et d'éviter la redondance.
Quoi de mieux? Définir des événements sur une collection ou des modifications de propriété sur le modèle de vue et le propager au modèle ou faire en sorte que la vue mette à jour intrinsèquement le modèle (via le modèle de vue)?
La ligne de fond chaque fois que vous voyez quelqu'un qui affirme que, "vous ne pouvez pas faire ceci ou cela" c'est un signe qu'ils ne savent pas de quoi ils parlent.
Cela dépend vraiment de votre cas et en fait MVVM est un framework avec beaucoup de problèmes et je n'ai pas encore vu une implémentation commune de MVVM dans tous les domaines.
J'aimerais avoir plus de temps pour expliquer les nombreuses saveurs de MVVM et quelques solutions aux problèmes communs - la plupart du temps fournis par d'autres développeurs, mais je suppose que je vais devoir le faire une autre fois.
Dans M-V - VM, ViewModel toujours (modèle pas toujours) implémente INotifyPropertyChanged
Consultez le modèle de projet M-V-VM / Toolkit de http://blogs.msdn.com/llobo/archive/2009/05/01/download-m-v-vm-project-template-toolkit.aspx.
Il utilise le DelegateCommand
pour commander et il devrait être un excellent modèle de départ pour vos projets M-V-VM.
Je pense que MVVM est très mal nommé et appeler ViewModel un ViewModel fait manquer à beaucoup une caractéristique importante d'une architecture bien conçue, qui est un contrôleur de données qui contrôle les données, peu importe qui essaie de le toucher.
Si vous considérez le modèle de vue comme un contrôleur de données et implémentez une architecture où votre contrôleur de données est le seul élément qui touche les données, vous ne toucherez jamais directement les données, mais utilisez toujours le contrôleur de données. Le DataController est utile de l'INTERFACE utilisateur, mais pas nécessairement seulement pour l'INTERFACE utilisateur. C'est pour la couche business, la couche UI, etc...
DataModel -------- DataController ------ View
/
Business --------/
, vous Vous retrouvez avec un modèle comme celui-ci. Même l'entreprise ne devrait toucher les données qu'à l'aide du ViewModel. Ensuite, votre énigme disparaît.
Cela dépend de la façon dont vous avez implémenté votre modèle. Mon entreprise utilise des objets métier similaires aux objets CSLA de Lhotka et utilise largement INotifyPropertyChanged tout au long du modèle d'affaires.
Notre moteur de validation repose fortement sur la notification que les propriétés changent grâce à ce mécanisme et cela fonctionne très bien. Évidemment, si vous utilisez une implémentation différente autre que les objets métier où la notification des modifications n'est pas aussi critique pour l'opération, vous pouvez avoir d'autres méthodes pour détecter les changements dans votre modèle d'affaires.
Nous avons également des modèles de vue qui propagent les changements du modèle si nécessaire, mais les Modèles de vue eux-mêmes écoutent les changements de modèle sous-jacents.
Je pense que la réponse est assez claire si vous souhaitez adhérer à la MV-VM.
Voir: http://msdn.microsoft.com/en-us/library/gg405484 (V = PandP.40).aspx
Dans le modèle MVVM, la vue encapsule l'interface utilisateur et toute logique D'interface utilisateur, le modèle de vue encapsule la logique de présentation et l'état, et le modèle encapsule la logique métier et les données.
" la vue interagit avec le modèle de vue via la liaison de données, les commandes et les événements de notification de modification. Les requêtes de modèle de vue, observe et coordonne les mises à jour du modèle, convertit, valide et agrège les données nécessaires à l'affichage dans la vue. "
Je dirais dans votre ViewModel. Cela ne fait pas partie du modèle car le modèle est agnostique de L'interface utilisateur. Le modèle devrait être 'tout sauf agnostique'
Mais parfois (comme dans cette présentation Texte de lien) le modèle est un service, qui fournit une application avec des données en ligne et vous devez remplir la notification que de nouvelles données sont arrivées ou que les données ont changé en utilisant des événements...
Je pense que tout dépend du cas d'utilisation.
Lorsque vous avez un modèle simple avec des charges de propriétés, Vous pouvez le faire implémenter INPC. Par simple, je veux dire que ce modèle ressemble plutôt à un POCO .
Si votre modèle est plus complexe et vit dans un domaine de modèle interactif-modèles référençant des modèles, s'abonner aux événements d'autres modèles - avoir des événements de modèle implémentés comme INPC est un cauchemar.
Mettez-vous dans une position d'une entité modèle qui doit colaborer avec certains autres modèles. Vous avez divers événements pour vous abonner. Tous sont implémentés comme INPC. Imaginez les gestionnaires d'événements que vous avez. Une énorme cascade de clauses if et / ou de clausses switch.
Un autre problème avec INPC. Vous devez concevoir vos applications pour s'appuyer sur l'abstraction, pas sur l'implémentation. Ceci est généralement fait en utilisant des interfaces.
Regardons 2 implémentations différentes de la même abstraction:
public class ConnectionStateChangedEventArgs : EventArgs
{
public bool IsConnected {get;set;}
}
interface IConnectionManagerINPC : INotifyPropertyChanged
{
string Name {get;}
int ConnectionsLimit {get;}
/*
A few more properties
*/
bool IsConnected {get;}
}
interface IConnectionManager
{
string Name {get;}
int ConnectionsLimit {get;}
/*
A few more properties
*/
event EventHandler<ConnectionStateChangedEventArgs> ConnectionStateChanged;
bool IsConnected {get;}
}
Regardez maintenant les deux. Ce n' IConnectionManagerINPC vous dire? Que certaines de ses propriétés peuvent changer. Vous ne savez pas lequel d'entre eux. En fait, la conception est que Seulementchangements connectés, car le reste d'entre eux sont en lecture seule.
Au contraire, les intentions D'IConnectionManager sont claires: "je peux vous dire que la valeur de ma propriété IsConnected peut changer".
Utilisez simplement le INotifyPropertyChange
dans votre viewmodel et non dans le modèle,
Le modèle utilise généralement le IDataErrorInfo
pour gérer les erreurs de validation, il suffit donc de garder dans votre ViewModel et vous êtes sur votre route MVVM.
Je suis d'accord avec la réponse de Paulo, l'implémentation de INotifyPropertyChanged
dans les modèles est totalement acceptable et est même suggérée par Microsoft -
Typiquement, le modèle implémente les installations qui le rendent facile à lier à la vue. Cela signifie généralement qu'il prend en charge la propriété et la collecte a changé de notification via
INotifyPropertyChanged
etINotifyCollectionChanged
interfaces. Modèles classes qui représentent les collections d'objets dérivent généralement duObservableCollection<T>
classe, qui fournit une implémentation de laINotifyCollectionChanged
interface.
Bien que c'est à vous de décider si vous voulez ce type d'implémentation ou non, mais rappelez-vous -
Que faire si vos classes de modèle n'implémentent pas les interfaces requises?
Parfois, vous devrez travailler avec des objets de modèle qui ne le font pas implémentez le
INotifyPropertyChanged
,INotifyCollectionChanged
,IDataErrorInfo
, ouINotifyDataErrorInfo
interfaces. Dans ces cas, le modèle de vue peut avoir besoin d'envelopper les objets du modèle et d'exposer propriétés requises pour la vue. Le les valeurs de ces propriétés être fourni directement par les objets du modèle. La vue modèle implémentez les interfaces requises pour les propriétés qu'il expose ainsi que la vue peut facilement lier les données à eux.
Tiré de - http://msdn.microsoft.com/en-us/library/gg405484 (PandP.40).aspx
J'ai travaillé dans certains projets où nous n'avons pas implémenté INotifyPropertyChanged
dans nos modèles et à cause de cela, nous avons rencontré beaucoup de problèmes; la duplication inutile des propriétés était nécessaire dans VM et en même temps nous avons dû mettre à jour l'objet sous-jacent(avec des valeurs mises à jour) avant de les transmettre à BL/DL.
Vous rencontrerez des problèmes spécialement si vous devez travailler avec la collection de vos objets de modèle (disons dans une grille ou une liste modifiable) ou des modèles complexes; les objets de modèle ne seront pas mis à jour automatiquement et vous devrez gérer tout cela dans votre machine virtuelle.
Initialement répondu à une autre question similaire, en ajoutant ici car il contient imp. détails manquants à partir de ce fil -
Supposons que la référence de l'objet dans votre vue change. Comment allez-vous notifier toutes les propriétés à mettre à jour afin d'afficher les valeurs correctes? Appeler OnPropertyChanged
dans votre vue pour toutes les propriétés de l'objet est inutile à mon point de vue.
Donc, ce que je fais est de laisser l'objet lui-même avertir quiconque lorsqu'une valeur dans une propriété change, et à mon avis, j'utilise des liaisons comme Object.Property1
, Object.Property2
et après. De cette façon si je veux juste changer l'objet qui est actuellement maintenu à mon avis je viens faites OnPropertyChanged("Object")
.
Pour éviter des centaines de notifications pendant le chargement des objets, j'ai un indicateur booléen privé que je l'ai mis à true pendant le chargement qui est vérifié à partir de OnPropertyChanged
de l'objet et ne fait rien.
J'utilise l'interface INotifyPropertyChange
dans un modèle. En fait, une modification de propriété de modèle ne doit être déclenchée que par L'interface utilisateur ou le client externe.
J'ai remarqué plusieurs avantages et inconvénients:
Avantages
Notifiant est dans le modèle d'affaires
- selon le domaine piloté, c'est juste. Il devrait décider quand soulever et quand ne pas.
Inconvénients
Le modèle a des propriétés (qty, rate, commission, totalfrieght). Totalfrieght est calculé en utilisant la quantité, le taux, le changement de commission.
Sur les valeurs de chargement de db, le calcul total frieght est appelé 3 fois (quantité, taux, commission). Ça devrait être une fois.
Si rate, qty est affecté dans la couche métier, encore une fois notifier est appelé.
Il devrait y avoir une option pour désactiver cela, éventuellement dans la classe de base. Cependant, les développeurs pourraient oublier de le faire.
À mon humble avis, je pense que viewmodel implémente INotifyPropertyChange
et que le modèle pourrait utiliser la notification à un "niveau" différent.
Par exemple avec un service de document et un objet document, vous avez un événement documentChanged qu'un viewmodel écoute pour effacer et reconstruire la vue. Dans l'édition viewmodel, vous avez un propertychange pour les propriétés du document pour prendre en charge les vues. Si le service fait beaucoup avec le document en sauvegarde (mise à jour de la date de changement, dernier utilisateur, etc.), vous obtenez facilement une surcharge des événements Ipropertychanged et juste un documentchanged est suffisant.
Mais si vous utilisez INotifyPropertyChange
dans votre modèle, je pense qu'il est bon de le relayer dans votre viewmodel au lieu de s'y abonner directement dans votre vue. Dans ce cas, lorsque les événements changent dans votre modèle, il vous suffit de changer le viewmodel et la vue reste intacte.