web-dev-qa-db-fra.com

Pourquoi éviter le code derrière dans le modèle WPF MVVM?

Dans l'article, WPF Apps With The Model-View-ViewModel Design Pattern , l'auteur qui est Josh Smith a déclaré:

(1) Dans une architecture MVVM bien conçue, le code derrière pour la plupart des vues doit être vide ou, tout au plus, contenir uniquement du code qui manipule les contrôles et les ressources contenus dans cette vue. (2) Parfois, il est également nécessaire d'écrire du code dans le code derrière une vue qui interagit avec un objet ViewModel, comme accrocher un événement ou appeler une méthode qui serait autrement très difficile à appeler à partir du ViewModel lui-même.

Ma question est, au (1), pourquoi le codebehind vide est considéré comme un MVVM bien conçu.(Il semble que le code vide derrière soit toujours bon.)

EDIT: Ma question est, comme suit, pourquoi l'approche comme le AttachedCommandBehavior ou le InvokeCommandAction est essayée pour éviter le code derrière le codage.

Permettez-moi d'expliquer plus en détail.

En ce qui concerne le (1), je penserais comme la situation suivante à partir du AttachedCommandBehavior . Comme la bordure n'implémente pas le ICommandSource pour le MouseRightButtonDown, vous ne pouvez généralement pas lier l'événement et le ICommand, mais vous pouvez le faire avec AttachedCommandBehavior =.

<!-- I modified some code from the AttachedCommandBehavior to show more simply -->
<Border>
    <local:CommandBehaviorCollection.Behaviors>
           <local:BehaviorBinding Event="MouseRightButtonDown" 
                  Command="{Binding SomeCommand}" 
                  CommandParameter="A Command on MouseRightButtonDown"/>
    </local:CommandBehaviorCollection.Behaviors>
</Border>

[~ # ~] ou [~ # ~]

Nous pouvons le faire avec le System.Windows.Interactivity.InvokeCommandAction.

<Border xmlns:i="clr-namespace:System.Windows.Interactivity;Assembly=System.Windows.Interactivity" >
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="MouseRightButtonDown">
            <i:InvokeCommandAction Command="{Binding SomeCommand}" 
               CommandParameter="A Command on MouseRightButtonDown"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
</Border>

MAIS,

Nous utilisons le XAML suivant et son code derrière le Border_MouseRightButtonDown méthode, qui est liée à (2) Josh Simth dit ci-dessus.

<Border MouseRightButtonDown ="Border_MouseRightButtonDown"/>

Je pense que l'utilisation du codebehind comme ci-dessus n'est pas mauvaise simplement parce que la différence entre ceux-ci ne concerne que la liaison d'une commande ou l'ajout d'un gestionnaire d'événements.

Que penses-tu de cela?

46
Jin-Wook Chung

pourquoi le codebehind vide est considéré comme un MVVM bien conçu

Avoir un fichier code-behind qui consiste uniquement en un appel à InitializeComponent () dans son constructeur signifie que vous avez atteint la pureté - vous n'avez absolument aucune logique dans votre codebehind. Vous n'avez pollué votre vue avec aucun code qui appartient à juste titre au modèle de vue ou au modèle. Cela signifie plusieurs choses:

  • le modèle de vue (et le modèle) est plus facile à tester isolément
  • vous avez atteint un bon niveau de couplage desserré, ce qui présente d'excellents avantages du point de vue de la maintenance et de l'extensibilité

Les avantages deviennent vraiment perceptibles lorsque vous devez modifier votre interface utilisateur, c'est-à-dire que vous passez de l'utilisation d'un ListView à un DataGrid, ou que vous passez de l'utilisation des contrôles Microsoft standard à l'utilisation d'un autre fournisseur.

Comme mentionné cependant, il est parfois impossible d'éviter un peu de code dans le fichier code-behind. Ce que vous devez vous assurer, c'est que le code que vous avez est purement lié à l'interface utilisateur. Par exemple, si vous avez ComboA et ComboB et que ComboB est défini en réponse à la sélection dans ComboA, la définition de SelectedIndex of ComboB dans la vue est correcte, mais la définition des éléments ou de SelectedItem of ComboB ne l'est pas - ces propriétés sont les deux sont liées aux données et doivent être spécifiées via une liaison avec le modèle de vue. La propriété SelectedIndex est directement liée visuellement et quelque peu indépendante des données réelles (et elle n'est pas pertinente pour le modèle d'affichage).

Si vous accédez au viewmodel depuis le code-behind de la vue, vous devriez essayer de le faire via une interface. Cela signifie que votre modèle de vue est injecté ou donné à la vue sous forme d'interface. (Notez que le sous-système de liaison ne connaît pas ou ne se soucie pas de l'interface, il continuera à se lier de sa manière normale. Ce que cela permet d'obtenir un meilleur code, avec un couplage moins serré). De la façon dont je le code, le viewmodel n'a aucune idée qu'il existe une vue, et la vue ne connaît que le viewmodel en tant qu'interface.

Cependant, une chose à retenir est que MVVM est un modèle, et un modèle est simplement un recette ou prescription pour obtenir un certain résultat dans une certaine situation. Elle ne devrait pas être traitée comme une religion, où les non-croyants ou les non-conformistes iront dans un purgatoire (bien que l'adhésion au modèle soit bonne si vous voulez éviter le purgatoire de enfer de maintenance et odeur de code ).

Si vous voulez un excellent exemple de la façon dont ce modèle particulier aide, essayez d'écrire quelques écrans raisonnablement compliqués dans ASP.Net, puis écrivez-les dans WPF ou Silverlight, et notez la différence.


Modifier:

permettez-moi de répondre à certaines de vos questions, j'espère que cela vous aidera ...

le rôle du modèle de vue (modèle de vue), à ​​mon avis, a une logique d'interface utilisateur et un état de vue

Le modèle de vue ne doit jamais contenir de logique d'interface utilisateur ni d '"état d'affichage". Pour les besoins de cette explication, je définirais l'état de la vue comme la position de défilement, l'index de ligne sélectionné, l'index sélectionné, la taille de la fenêtre, etc. des éléments comme SelectedIndex sont spécifiques à la façon dont les données sont affichées dans l'interface utilisateur (si vous modifiez l'ordre de tri d'un DataGrid, le SelectedIndex peut changer, même si le SelectedItem est toujours le même). Dans ce cas particulier, le SelectedItem peut être lié au viewmodel, mais le SelectedIndex ne devrait pas.
. avec un appel au viewmodel (via l'interface que j'ai mentionnée précédemment). La vue n'a aucune idée de la façon dont les données sont enregistrées, et le modèle de vue n'a aucune idée que les données proviennent d'une vue (il a simplement exposé un appel via son interface).

et le rôle de la vue est d'afficher certains contenus et de synchroniser le modèle de vue (ayant un code de liaison de données)

Oui, la responsabilité de la vue consiste simplement à afficher visuellement les données présentées par le modèle de vue. Le modèle de vue obtient les données du modèle (le modèle est responsable des appels de base de données ou des appels de service Web WCF, cela se fera généralement via un "service", mais c'est une toute autre discussion). Le modèle de vue peut ensuite façonner ou manipuler les données, c'est-à-dire qu'il peut obtenir une liste de tous les clients, mais uniquement exposer une version filtrée de cette liste (peut-être les clients actuels) dans une propriété publique à laquelle la vue peut ensuite se lier.
Si les données doivent être manipulées en quelque chose de visuel (un exemple courant est une valeur d'énumération traduite en couleur), alors le viewmodel n'a toujours que la ou les valeurs d'énumération, et la vue se lie toujours à cette valeur. mais la vue aussi tilise un convertisseur pour traduire les données pures en représentation visuelle. En utilisant le convertisseur, le modèle de vue a toujours évité de faire quoi que ce soit lié à l'interface utilisateur, et la vue a évité toute logique réelle.

65
slugster

Le MVVM peut diviser complètement la conception du code et de la page; les codeurs ne se soucient que du codage et les concepteurs ne se soucient que du design. Mais:

  1. Je n'ai jamais vu de concepteur utiliser Blend ou comprendre XAML.
  2. Presque tous les XAML sont écrits par le codeur lui-même.
8
user4276887

Il n'y a rien de intrinsèquement mauvais dans le code-behind. Pour les cas simples, c'est bien de l'avoir. Cependant, la logique de l'interface utilisateur peut devenir difficile à gérer dans de nombreux scénarios. L'encapsulation de cette logique dans les comportements attachés et les modèles de vue nous permet d'isoler les variables (et de les tester) afin qu'elles soient plus faciles à comprendre et à maintenir.

Si la testabilité est un problème, plus vous pouvez encapsuler votre logique d'interface utilisateur dans les modèles de vue et les comportements associés, plus vous pourrez vérifier sans recourir aux tests d'interface utilisateur. (Bien qu'il n'élimine pas complètement le besoin de tests d'interface utilisateur, il fournit un premier niveau de vérification avant de s'engager dans des tests d'interface utilisateur qui nécessiteront plus de temps/de ressources.

5
Michael Brown

Je pense que la section citée fait référence à la façon dont les données sont visualisées. Je pense qu'ils signifient que vous ne devriez pas écrire de code dans le code derrière qui est, par exemple, lié à la façon ou à l'endroit où les données sont affichées (par exemple quelque chose comme: label1.Text = ...). Faire des choses comme ça en utilisant des liaisons facilite la séparation de la conception et du code (que se passe-t-il si vous avez besoin que les données soient affichées dans une zone de texte nommée "tbTest" dans une version ultérieure? Vous devrez changer votre code derrière).

Ils ne disent pas que vous ne devriez pas avoir de code dans le code derrière - ils disent simplement que dans un monde idéal, vous ne réagiriez qu'à des événements ou traiteriez des données qui autrement ne pourraient pas être traitées.

C'est du moins ce que je comprends de la section que vous avez citée.

2
Thorsten Dittmar