MVVM: ViewModel et Business Logic Connection

après avoir fait quelques projets en utilisant le modèle MVVM, Je suis toujours aux prises avec le rôle du modèle de vue:

ce que j'ai fait dans le passé: Utiliser le modèle uniquement comme un conteneur de données. Mettre la logique pour manipuler les données dans le Modèlevue. (C'est la Logique des Affaires de droit?) Con: la logique n'est pas réutilisable.

ce que j'essaie maintenant: Garder le modèle de vue aussi fin que possible. Déplacer toute logique dans la couche modèle. Ne conserver que la logique de présentation le ViewModel. Con: rend la Notification D'UI vraiment douloureuse si les données sont changées à l'intérieur de la couche Model.

donc je vais vous donner un exemple pour le rendre plus clair:

Scénario

: Outil pour renommer les fichiers. Classe: Fichier: représentation de chaque fichier; Règle: contient la logique comment renommer un fichier;

si la GI suit l'approche 1: Création d'un ViewModel pour le fichier, la règle et la vue -> RenamerViewModel. Mettre toute la logique dans le modèle Renamerview: Contenant une liste de FileViewModel et de RuleViewModel et la logique de la procédure. Facile et rapide, mais n'est pas réutilisable.

si la GI suit l'approche 2: Création d'une nouvelle classe Model -> Renamer, qui contient une liste de fichier, règle et la logique de la procédure pour interagir sur chaque fichier et appliquer chaque règle. Création d'un Viewmodel pour File, Rule et Renamer. Maintenant le RenamerViewModel ne contient qu'une instance du modèle Renamer, plus deux collections observables pour envelopper le fichier et la liste des règles de le Renommeur. Mais toute la logique est dans le modèle Renamer. Ainsi, si le modèle Renamer est déclenché pour manipuler certaines données par des appels de méthode, le ViewModel n'a aucune idée des données qui sont manipulées. Parce que le modèle ne contient pas de Notification de changement de propriété et je vais éviter cela. Ainsi, la logique D'affaires et de présentation est séparée, mais cela rend difficile de notifier L'UI.

31
demandé sur JDeuker 2013-05-02 16:51:38

4 réponses

mettre la logique des affaires dans le modèle de vue est une très mauvaise façon de faire les choses, donc je vais rapidement dire ne faites jamais cela et passer à la discussion de la deuxième option.

mettre la logique à l'intérieur du modèle est beaucoup plus raisonnable et c'est une bonne approche de départ. Quels sont les inconvénients? Votre question dit

donc si le modèle Renamer est déclenché pour manipuler certaines données par la méthode Les appels, les ViewModel ne sait pas quelles données sont manipulées. Parce le modèle ne contient pas de Notification de modification de propriété et je vais l'éviter.

bien, faire votre modèle implémenter INotifyPropertyChanged vous permettrait certainement de passer à des choses meilleures. Cependant, il est vrai que parfois il n'est pas possible de faire cela -- par exemple le modèle peut être une classe partielle où les propriétés sont générées automatiquement par un outil et ne soulèvent pas de notifications de changement. C'est malheureux, mais pas la fin du monde.

si vous voulez acheter quelque chose alors quelqu'un doit payer pour cela; si ce n'est pas le modèle qui donne de telles notifications alors vous êtes laissés avec seulement deux choix:

  1. le modèle de vue sait quelles opérations sur le modèle provoquent (éventuellement) des changements et il met à jour son état après chaque telle opération.
  2. Quelqu'un d'autre sait quelles opérations provoquent des changements et ils aviser ce dernier de mettre à jour son état après le modèle, il est enveloppant changements.

la première option est à nouveau une mauvaise idée, car elle revient en fait à remettre la "logique des affaires" dans le modèle de vue. Pas aussi mauvais que de mettre tout la logique d'affaires dans le modèle de vue, mais tout de même.

la deuxième option est plus prometteuse (et malheureusement plus de travail à mettre en œuvre):

  • Mettez une partie de votre logique d'entreprise dans une classe séparée (un "service"). Le service mettra en œuvre toutes les opérations opérationnelles que vous souhaitez effectuer en travaillant avec des instances modèles, selon les besoins.
  • cela signifie que le service sait quand les propriétés du modèle peuvent changer (C'est OK: model + service == business logic).
  • le service fournira des notifications sur les modèles modifiés à toutes les parties intéressées; vos modèles de vue prendront une dépendance sur le service et recevoir ces notifications (afin qu'ils sachent quand "leur" modèle a été mis à jour).
  • étant donné que les opérations commerciales sont également mises en œuvre par le service, cela reste très naturel (par exemple, lorsqu'une commande est invoquée sur le modèle de vue, la réaction appelle une méthode appropriée sur le service; rappelez-vous, le modèle de vue lui-même ne connaît pas la logique commerciale).

pour plus d'informations sur une telle mise en œuvre, Voir aussi mes réponses ici et ici .

41
répondu Jon 2017-05-23 11:54:08

les deux approches sont valables, mais il y a une troisième approche: implémenter un service entre le modèle et les couches VM. Si vous voulez garder vos modèles muets, un service peut fournir un intermédiaire UI-agnostique qui peut appliquer vos règles d'affaires d'une manière réutilisable.

parce que le modèle ne contient pas de Notification de changement de propriété et je vais éviter que

pourquoi évites-tu cela? Ne vous méprenez pas, j'ai tendance à gardez mes modèles aussi muets que possible, mais implémenter la notification de changement dans votre modèle peut parfois être utile, et vous ne prenez une dépendance que sur System.ComponentModel quand vous le faites. C'est complètement agnostique.

12
répondu Kent Boogaart 2013-05-02 13:10:03

je fais ce qui suit

  1. voir avec XAML vue logique

  2. ViewModel qui gère les gestionnaires de clic et la création de nouveaux modèles de vue. Gère les événements routés etc.

  3. modèle qui est mon conteneur de données et la logique commerciale concernant la validation des données du modèle.

  4. Services qui peuplent le modèle avec données. Par exemple appeler un serveur web, charger à partir du disque, enregistrer sur le disque, etc. Selon l'exemple souvent mon modèle et le service implémenteront IPropertyChanged. Ou ils peuvent avoir des gestionnaires d'événements à la place.

toute application complexe imo a besoin d'une autre couche. Je l'appelle modèle de service, vue, viewmodel. Le service résume votre logique d'entreprise et prend une instance de modèle comme une dépendance ou crée un modèle.

1
répondu rolls 2017-10-14 10:23:03

vous pouvez également implémenter IDataErrorInfo à la fois sur: Model et ViewModel, mais en faisant la validation uniquement dans Model, cela vous facilitera la mise en œuvre des règles commerciales uniquement dans Model ...

Ex:

ViewModel:

...

private Person person;

...

string IDataErrorInfo.this[string propertyName]
{
    get
    {
        string error = (person as IDataErrorInfo)[propertyName];
        return error;
    }
}

Modèle:

public class Person:INotifyPropertyChanged,IDataErrorInfo
{

...

   string IDataErrorInfo.this[string propertyName]
   {
        get { return this.GetValidationError(propertyName); }
   }

...

   string GetValidationError(string propertyName)
   {
        if(propertyName == "PersonName")
             //do the validation here returning the string error
   }
}

plus jetez un oeil au Modèle MVCVM, Je l'utilise réellement et il est assez facile de faire abstraction de la logique d'affaires à une classe de contrôleur au lieu du modèle ou de la viewmodèle

0
répondu Rafael A. M. S. 2013-09-17 15:16:27