WPF MVVM Warum ContentControl + DataTemplate-Ansichten anstelle von geraden XAML-Fensteransichten verwenden?

82

Warum das?

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>

Lassen Sie Ihre ExampleView.xaml wie folgt einrichten:

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

Und erstellen Sie das Fenster wie folgt:

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();
    }
}

Wann geht das so?

App.xaml: (Startfenster / Ansicht einstellen)

<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: (ein Fenster, kein 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>

Im Wesentlichen ist es "View as DataTemplate" (VaD) vs. "View as Window" (VaW)

Hier ist mein Verständnis des Vergleichs:

  • VaD: Ermöglicht das Wechseln der Ansicht, ohne das Fenster zu schließen. (Dies ist für mein Projekt nicht wünschenswert)
  • VaD: VM weiß absolut nichts über die Ansicht, während sie in VaW (nur) in der Lage sein muss, sie beim Öffnen eines anderen Fensters zu instanziieren
  • VaW: Ich kann meine xaml tatsächlich im Designer sehen (ich kann nicht mit VaD, zumindest in meinem aktuellen Setup).
  • VaW: Funktioniert intuitiv beim Öffnen und Schließen von Fenstern. Jedes Fenster hat (ist) eine entsprechende Ansicht (und ViewModel)
  • VaD: ViewModel kann die anfängliche Fensterbreite, -höhe, -anpassbarkeit usw. über Eigenschaften weitergeben (während sie in VaW direkt im Fenster festgelegt werden).
  • VaW: Kann FocusManager.FocusedElement einstellen (nicht sicher, wie in VaD)
  • VaW: Weniger Dateien, da meine Fenstertypen (z. B. Multifunktionsleiste, Dialogfeld) in ihre Ansichten integriert sind

Also, was ist hier los? Kann ich meine Fenster nicht einfach in XAML erstellen, über die Eigenschaften der VM sauber auf ihre Daten zugreifen und damit fertig sein? Der Code-Behind ist der gleiche (praktisch Null).

Ich habe Probleme zu verstehen, warum ich das gesamte View-Material in ein ResourceDictionary mischen sollte.

Simon F.
quelle
2
Stellen Sie sich Folgendes vor: ViewModels sollen entweder in Windows oder in UserControls angezeigt werden. Pocos werden in DataTemplates angezeigt. :)
Dev Hedgehog

Antworten:

129

Benutzer verwenden DataTemplatesdiese Methode, wenn sie die Ansicht je nach ViewModel dynamisch wechseln möchten:

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

So,

Wenn Window.DataContextes sich um eine Instanz von handelt VM1, View1wird Folgendes angezeigt:

und wenn

Window.DataContextist eine Instanz von VM2, View2wird dann angezeigt.

Zugegeben, es macht überhaupt keinen Sinn, wenn nur 1 Ansicht erwartet und nie geändert wird.

Federico Berasategui
quelle
8

Da die Ansichtsmodelle in VaD nichts über die Ansichten wissen, können Sie eine voll funktionsfähige Anwendung erstellen, die ausschließlich aus Ansichtsmodellen und keinen Ansichten besteht. Dies führt zu der Möglichkeit, eine Anwendung zu schreiben, die vollständig vom Code gesteuert werden kann. Dies führt wiederum zu der Möglichkeit, Integrationstests ohne die GUI durchzuführen. Integrationstests über die GUI sind bekanntermaßen fragil - während Tests über Ansichtsmodelle robuster sein sollten.

Phillip Ngan
quelle
5

Aus meiner persönlichen Erfahrung: Beide Arbeitsmodelle sind verfügbar, je nachdem, was Sie möchten und je nach den Anwendungsanforderungen. Die Idee dahinter VaDist, den Inhalt und den Container zu entschlüsseln. Wenn Sie implementieren VaD, können Sie diese Vorlage (standardmäßig) verwenden, wenn Sie ein Element dieses Typs anzeigen. Sie können es in ItemsControls(Listen, Listenansichten, Raster usw.) und ContentControlsnur zum Erstellen von Bindungen verwenden. Wie Sie sagten, VaDfunktioniert das Wechseln des Fensterinhalts, ohne ein neues zu schließen und zu öffnen. Sie können die Ansicht auch mit definieren UserControls, dann die Kontrolle über fokussierte Elemente übernehmen und den Code dahinter verwalten. Ihre Datenvorlage könnte also folgendermaßen aussehen:

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

Sie können auch UserControlAbhängigkeitseigenschaften festlegen, die den Job erleichtern, da Sie Bindungen zulassen und die App entkoppeln können.

Wenn Ihre App jedoch keine dynamische Inhaltsumschaltung erfordert, ist es natürlich in Ordnung, sie VaWfür das Hauptfenster oder ein anderes Fenster zu verwenden. In der Tat können Sie beide VaWund verwenden VaD. Letzteres kann für innere Elemente in der App verwendet werden, für die keine Fenster erforderlich sind. Sie entscheiden, was für Sie besser ist, abhängig von den Anwendungsanforderungen und der Zeit, die für die Entwicklung der App zur Verfügung steht. Hoffe diese persönliche Erfahrung hilft ...

Raúl Otaño
quelle