it-swarm.com.de

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

Ich habe eine Frage zu MVVM in WPF, die mich verrückt macht.

Warum so etwas machen:?

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>

Haben Sie Ihre ExampleView.xaml eingerichtet als:

<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 erstelle das Fenster so:

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

Wenn du es so machen kannst:?

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 "Als DataTemplate anzeigen" (VaD) vs. "Als Fenster anzeigen" (VaW)

Hier ist mein Verständnis des Vergleichs: (Hinweis: Ich verwende VS 2008, daher fehlt mir die Mischbarkeit und/oder anderes Material.)

  • VaD: Hiermit können Sie die Ansicht wechseln, 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 es in VaW (nur) in der Lage sein muss, sie zu instanziieren, wenn ein anderes Fenster geöffnet wird
  • VaW: Ich kann meine im Designer gerenderte XAML tatsächlich sehen (ich kann mit VaD nicht, zumindest in meinem aktuellen Setup)
  • VaW: Arbeitet intuitiv mit dem Öffnen und Schließen von Fenstern. Jedes Fenster hat (ist) eine entsprechende Ansicht (und ViewModel)
  • VaD: ViewModel kann die anfängliche Fensterbreite, -höhe, -größe usw. über Eigenschaften übergeben (während sie in VaW direkt im Fenster festgelegt werden).
  • VaW: Kann FocusManager.FocusedElement setzen (nicht sicher, wie in VaD)
  • VaW: Weniger Dateien, da meine Fenstertypen (z. B. Multifunktionsleiste, Dialogfeld) in ihren Ansichten enthalten 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 werden? Der Code-Behind ist derselbe (praktisch null). Ich habe Probleme zu verstehen, warum ich das gesamte View-Material in ein ResourceDictionary mischen sollte. (Aber ich will es nicht falsch machen ;-))


Ist es überhaupt wichtig? Gibt es etwas, das ich verpasst habe? Vielen Dank fürs Lesen. :O


Vielen Dank an Rachel Lim und Nick Polyak für mein blühendes Verständnis von MVVM

Bearbeiten: Kleine Durchflussänderung

74
Simon F

Die Benutzer verwenden DataTemplates auf diese Weise, wenn sie Ansichten abhängig vom 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,

ob Window.DataContext ist eine Instanz von VM1, dann View1 wird Angezeigt werden,

und wenn

Window.DataContext ist eine Instanz von VM2, dann View2 wird Angezeigt werden.

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

Ich hoffe das ist klar genug: P

121

Da in VaD die Ansichtsmodelle 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 durch Code gesteuert werden kann. Dies führt wiederum zu der Möglichkeit, Integrationstests ohne die GUI durchzuführen. Integrationstests über die GUI sind notorisch anfällig - während Tests über Ansichtsmodelle robuster sein sollten.

8
Phillip Ngan

Aus meiner persönlichen Erfahrung: Beide Arbeitsmodelle sind verfügbar, je nachdem, was Sie wollen und je nach den Anwendungsanforderungen. Die Idee hinter VaD ist, den Inhalt und den Container zu dekopieren. Wenn Sie VaD implementieren, können Sie diese Vorlage (standardmäßig) immer dann verwenden, wenn Sie Elemente dieses Typs anzeigen. Sie können es in ItemsControls (Listen, Listenansichten, Rastern usw.) und in ContentControls verwenden, um nur Bindungen zu erstellen. Wie Sie sagten, funktioniert VaD, um den Inhalt des Fensters zu wechseln, ohne ein neues zu schließen und zu öffnen. Sie können die Ansicht auch mit UserControls definieren, dann die Kontrolle über fokussierte Elemente übernehmen und den Code dahinter verwalten. Ihre Datenvorlage könnte also so 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 in einem UserControl Abhängigkeitseigenschaften festlegen, die den Job erleichtern, da das Binden und Entkoppeln der App möglich ist.

Aber natürlich ist es in Ordnung, VaW für das Hauptfenster oder ein anderes Fenster zu verwenden, wenn Ihre App keine dynamische Inhaltsumschaltung erfordert. Tatsächlich können Sie sowohl VaW als auch VaD verwenden. 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 ...

5
Raúl Otaño