web-dev-qa-db-fra.com

WPF MVVM Pourquoi utiliser ContentControl + DataTemplate Views plutôt que des vues de fenêtre XAML directes?

J'ai une question sur MVVM dans WPF qui me motive.

Pourquoi faire quelque chose comme ça:?

MainWindow.xaml:

<Window x:Class="MVVMProject.MainWindow"
    xmlns="http://schemas.Microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.Microsoft.com/winfx/2006/xaml">
    <Grid>
        <ContentControl Content="{Binding}"/>
    </Grid>
</Window>

Faites que votre ExampleView.xaml soit configuré comme suit:

<ResourceDictionary xmlns="http://schemas.Microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.Microsoft.com/winfx/2006/xaml"
    xmlns:vms="clr-namespace:MVVMProject.ViewModels">
    <DataTemplate DataType="{x:Type vms:ExampleVM}" >
        <Grid>
            <ActualContent/>
        </Grid>
    </DataTemplate>
</ResourceDictionary>

Et créez la fenêtre comme ceci:

public partial class App : Application {

    protected override void OnStartup(StartupEventArgs e) {

        base.OnStartup(e);

        MainWindow app = new MainWindow();
        ExampleVM context = new ExampleVM();
        app.DataContext = context;
        app.Show();
    }
}

Quand vous pouvez le faire comme ça:?

App.xaml: (Définir la fenêtre de démarrage/Voir)

<Application x:Class="MVVMProject.App"
    xmlns="http://schemas.Microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.Microsoft.com/winfx/2006/xaml"
    StartupUri="ExampleView.xaml">
</Application>

ExampleView.xaml: (une fenêtre et non un ResourceDictionary)

<Window x:Class="MVVMProject.ExampleView"
    xmlns="http://schemas.Microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.Microsoft.com/winfx/2006/xaml"
    xmlns:vms="clr-namespace:MVVMProject.ViewModels">
    >
    <Window.DataContext>
        <vms:ExampleVM />
    </Window.DataContext>

    <Grid>
        <ActualContent/>
    </Grid>
</Window>

Il s’agit essentiellement de "View as DataTemplate" (VaD) vs. "View as Window" (VaW)

Voici ma compréhension de la comparaison: (notez que j'utilise VS 2008, donc je manque de souplesse et/ou d'autres choses)

  • VaD: vous permet de changer de vue sans fermer la fenêtre. (Ce n'est pas souhaitable pour mon projet)
  • VaD: VM ne connaît absolument rien de la vue, alors que dans VaW, il doit (uniquement) pouvoir l'instancier lors de l'ouverture d'une autre fenêtre
  • VaW: Je peux réellement voir mon xaml rendu dans Designer (je ne peux pas avec VaD, du moins dans ma configuration actuelle)
  • VaW: Fonctionne intuitivement avec l'ouverture et la fermeture des fenêtres. chaque fenêtre a (est) une vue correspondante (et ViewModel)
  • VaD: ViewModel peut transmettre la largeur, la hauteur, la redimensionnabilité, etc. de la fenêtre initiale via les propriétés (alors que dans VaW, elles sont directement définies dans la fenêtre).
  • VaW: Peut définir FocusManager.FocusedElement (je ne sais pas comment dans VaD)
  • VaW: Moins de fichiers, car mes types de fenêtres (par exemple, Ruban, Dialogue) sont incorporés dans leurs vues.

Alors qu'est-ce qui se passe ici? Est-ce que je ne peux pas simplement construire mes fenêtres en XAML, accéder à leurs données proprement par le biais des propriétés de la machine virtuelle et en finir? Le code-behind est le même (pratiquement nul). J'ai du mal à comprendre pourquoi je devrais mélanger tous les éléments de View dans un ResourceDictionary. (Mais je ne veux pas le faire mal ;-))


Est-ce même important? Y a-t-il quelque chose que j'ai raté? Merci beaucoup pour la lecture. : O


Merci à Rachel Lim et Nick Polyak pour ma compréhension épanouie de MVVM

Edit: changement de flux mineur

74
Simon F

Les gens utilisent DataTemplates de cette façon lorsqu'ils souhaitent basculer dynamiquement de vues en fonction du ViewModel:

<Window>
    <Window.Resources>
       <DataTemplate DataType="{x:Type local:VM1}">
          <!-- View 1 Here -->
       </DataTemplate>

       <DataTemplate DataType="{x:Type local:VM2}">
          <!-- View 2 here -->
       </DataTemplate>
    </Window.Resources>

    <ContentPresenter Content="{Binding}"/>

</Window>

Alors,

si Window.DataContext est une instance de VM1, puis View1 sera affiché,

et si

Window.DataContext est une instance de VM2, puis View2 sera affiché.

Certes, cela n'a aucun sens si une seule vue est attendue et n'a jamais changé.

J'espère que c'est assez clair: P

121

Comme dans VaD, les modèles de vue ne connaissent rien des vues, vous pouvez créer une application entièrement fonctionnelle entièrement composée de modèles de vue et non de vues. Cela conduit à la possibilité d'écrire une application qui peut être entièrement pilotée par un code. Cela conduit à la possibilité d'effectuer des tests d'intégration sans l'interface graphique. Les tests d'intégration via l'interface graphique sont notoirement fragiles - alors que les tests via les modèles de vues devraient être plus robustes.

8
Phillip Ngan

D'après mon expérience personnelle: les deux modèles de travail sont aviables, en fonction de vos souhaits et des exigences de l'application. L'idée derrière VaD est de décoder le contenu et le conteneur. Si vous implémentez VaD, vous pouvez utiliser ce modèle (par défaut) chaque fois que vous affichez un élément de ce type. Vous pouvez l'utiliser dans ItemsControls (listes, listes de vues, grilles, etc.) et dans ContentControls seulement pour créer des liaisons. Comme vous l'avez dit, VaD fonctionne pour changer le contenu de la fenêtre sans fermer ni ouvrir de nouveau. Vous pouvez aussi définir la vue en utilisant UserControls, vous prenez alors le contrôle des éléments ciblés et vous pouvez également gérer le code derrière. Ainsi, votre modèle de données peut ressembler à ceci:

<ResourceDictionary xmlns="http://schemas.Microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.Microsoft.com/winfx/2006/xaml"
xmlns:vms="clr-namespace:MVVMProject.ViewModels">
<DataTemplate DataType="{x:Type vms:ExampleVM}" >
    <CustomUserControl A="{Binding A}" B="{Binding B}" DataContext="{Binding}" .../>
</DataTemplate>

Vous pouvez également, dans un UserControl, définir des propriétés de dépendance, ce qui facilite la tâche, car autoriser les liaisons et découpler l’application.

Mais bien sûr, si votre application ne nécessite pas de changement de contenu dynamique, il est préférable d’utiliser VaW pour la fenêtre principale ou toute autre fenêtre. En fait, vous pouvez utiliser à la fois VaW et VaD. Ce dernier peut être utilisé pour les éléments internes de l'application, qui ne nécessite pas de fenêtres. Vous choisissez ce qui est le mieux pour vous, en fonction des besoins de l'application et du temps dont vous disposez pour développer l'application. J'espère que cette expérience personnelle aide ...

5
Raúl Otaño