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

别等时光非礼了梦想. 提交于 2019-12-09 02:43:29

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.

I'm hiding a lot of details here in terms of view-viewmodel interactions for OK and Cancel, but as long as you have a DataTemplate set up then this should render your view inside of a window.

I have my viewmodel-view datatemplates defined in my application's resource dictionary:

<DataTemplate DataType="{x:Type SaveDocumentChangesVM}">
    <SaveDocumentChangesView />
</DataTemplate>

Window to host the view:

<Window x:Class="CustomDialogWindow" 
        SizeToContent="WidthAndHeight" ShowInTaskbar="False">
    <ContentPresenter Name="DialogContentPresenter" />
</Window>

Constructor for the window:

public CustomDialogWindow(object viewModel, string dialogTitle)
{
    InitializeComponent();

    // A datatemplate will allow WPF to figure out how to render the window contents
    DialogContentPresenter.Content = viewModel;

    if (dialogTitle != null)
    {
        Title = dialogTitle;
    }
}

Show the dialog like this:

var vm = new SaveDocumentChangesVM();
var dialog = new CustomDialogWindow(vm, "This is my dialog");
dialog.ShowDialog();
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!