How do I load a UserControl into a ContentPresenter within a (WPF) Window?

Jackson Dean Goodwin picture Jackson Dean Goodwin · Dec 10, 2012 · Viewed 8.5k times · Source

I have a window that contains a Viewbox. In that Viewbox, I would like to have one of several views which I have already created as UserControls. I am using the MVVM (Model View View-Model) design pattern. I have searched for about an hour online, and I cannot find any examples or tutorials that explain how to display a UserControl using a ContentPresenter.

Answer

user1228 picture user1228 · Dec 10, 2012

Depends.

I think your main issue is that a ContentPresenter is only used within a control template. You can't just stick it in a Window and expect it to show the content of the window. I believe what you really need to do is to use a ContentControl to host your UI.

By binding your model to the Content property of this control, you can set up DataTemplates that contain the expected view for that model. I'll give you an abbreviated example. Note, this may not match your design, but it demonstrates how it all goes together.

First, for each view, create a Model (or ViewModel) which manages the data (and interaction) for that view.

public sealed class Dialog : INotifyPropertyChanged // or DependencyObject
{
    public string Input {get;set;} // INPC or DP implementation not shown
    public ICommand Cancel {get;set;}
    // class definition not shown
}

Next, define your View to be shown in the ContentPresenter

<UserControl x:Class="Herp.DialogView" 
    HideImplementationDetails="true">
    <Border BorderBrush="Red" BorderThickness="5">
        <TextBlock Text="{Binding Input}" />  
        <Button Command="{Binding Cancel}">Cancel</Button>
        <!-- etc etc -->      
    </Border>
</UserControl>

Next, in your window, add the ContentControl and the DataTemplate

<Window HideImplementationDetailsForBrevityOfXaml="true">
    <Window.Resources>
        <DataTemplate xmlns:t="clr-namespace:Herp" 
            DataType="{x:Type t:Dialog}">
            <t:DialogView />
        </DataTempalte>
    </Window.Resources>
    <ContentControl Content="{Binding}" />
</Window>

And finally set the DataContext of the Window to your Dialog model.

public MyWindow()
{
    InitializeComponent();
    DataContext = new Dialog();
}

This is how the logic flows:

  1. Your window is created.
  2. An instance of the Dialog control is set on the DataContext.
  3. The binding on the ContentControl is updated
  4. The default DataTemplateSelector of the ContentControl searches resources for a DataTemplate whose DataType is set to typeof(Dialog)
  5. It finds this DataTemplate within the Window's Resources
  6. The content of the DataTemplate is loaded and added as a visual child of the ContentControl

Any time the Content of the ContentControl changes, the same process repeats. So you can have many different models, each with a different DataTemplate containing a different UserControl, and every time you update the binding on the ContentControl you see the expected View.

With MVVM, you would bind a property of your ViewModel to the Content property (call it Current or something), then switch out the model within the property to the expected value depending on the ViewModel's current state. Note, within a ContentControl, whatever is set to the Content property becomes the DataContext of the immediate child of the ContentControl. Similar to how each ItemsSource within an ItemsControl is the DataContext of the visual tree defined within the ItemTemplate.