WPF MVVM Why use ContentControl + DataTemplate Views rather than straight XAML Window Views?

Simon F picture Simon F · Nov 8, 2013 · Viewed 83.5k times · Source

Why This?

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>

Have your ExampleView.xaml set up as:

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

And create the window like this:

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

When it can be done like this?

App.xaml: (Set startup window/View)

<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: (a Window not a 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>

Essentially it's "View as DataTemplate" (VaD) vs. "View as Window" (VaW)

Here is my understanding of the comparison:

  • VaD: Lets you switch Views without closing the window. (This is not desirable for my project)
  • VaD: VM knows absolutely nothing about the View, whereas in VaW it (only) has to be able to instantiate it when opening another window
  • VaW: I can actually see my xaml rendered in the Designer (I can't with VaD, at least in my current setup)
  • VaW: Works intuitively with opening and closing windows; each window has (is) a corresponding View (and ViewModel)
  • VaD: ViewModel can pass along initial window width, height, resizability etc. through properties (whereas in VaW they are directly set in the Window)
  • VaW: Can set FocusManager.FocusedElement (not sure how in VaD)
  • VaW: Less files, since my window types (e.g. Ribbon, Dialog) are incorporated into their Views

So what's going on here? Can't I just build my windows in XAML, access their data cleanly through properties of the VM, and be done with it? The code-behind is the same (virtually nil).

I'm struggling to understand why I should shuffle all the View stuff into a ResourceDictionary.

Answer

Federico Berasategui picture Federico Berasategui · Nov 8, 2013

People use DataTemplates that way when they want to dynamically switch Views depending on the 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>

So,

if Window.DataContext is an instance of VM1, then View1 will be displayed,

and if

Window.DataContext is an instance of VM2, then View2 will be displayed.

Granted, it makes no sense at all if only 1 View is expected, and never changed.