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é?

147
demandé sur Edward Tanguay 2009-04-21 15:57:00

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.

92
répondu Steven Robbins 2015-12-15 09:01:07

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.

126
répondu Paulo Sousa 2018-04-28 05:53:16

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.

27
répondu Soni Ali 2017-08-26 18:45:34

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.

9
répondu Rhyous 2013-02-11 22:43:56

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.

7
répondu Steve Mitcham 2009-04-21 12:55:52

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. "

3
répondu John D 2013-08-24 06:46:42

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'

2
répondu Steve Dunn 2009-04-21 12:48:55

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...

2
répondu Andrey Khataev 2009-11-10 14:07:02

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".

1
répondu dzendras 2013-02-19 13:12:28

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.

1
répondu Adam 2015-12-15 09:02:38

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 et INotifyCollectionChanged interfaces. Modèles classes qui représentent les collections d'objets dérivent généralement du ObservableCollection<T> classe, qui fournit une implémentation de la INotifyCollectionChanged 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, ou INotifyDataErrorInfo 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 -

Https://stackoverflow.com/a/6923833/45382

1
répondu akjoshi 2017-05-23 12:26:10

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.

0
répondu Dummy01 2011-08-23 07:15:45

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

  1. 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.

  1. Sur les valeurs de chargement de db, le calcul total frieght est appelé 3 fois (quantité, taux, commission). Ça devrait être une fois.

  2. Si rate, qty est affecté dans la couche métier, encore une fois notifier est appelé.

  3. 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.

0
répondu Anand Kumar 2011-09-21 14:33:21

Normalement ViewModel implémentera le INotifyPropertyChanged. Le modèle peut être n'importe quoi(fichier xml, base de données ou même objet). Model est utilisé pour donner les données au viewmodel, qui se propage à la vue.

Voir ici

0
répondu Syed 2015-12-15 09:02:54

À 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.

0
répondu Bram 2016-04-26 04:35:21