如何将 UserControl 加载到 (WPF) 窗口内的 ContentPresenter 中?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13806473/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 06:33:24  来源:igfitidea点击:

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

wpfmvvmuser-controlscontentpresenter

提问by Hymanson Dean Goodwin

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.

我有一个包含 Viewbox 的窗口。在那个 Viewbox 中,我想拥有我已经创建为 UserControls 的几个视图之一。我正在使用 MVVM(模型视图视图模型)设计模式。我在网上搜索了大约一个小时,但找不到任何示例或教程来解释如何使用ContentPresenter.

回答by

Depends.

要看。

I think your main issue is that a ContentPresenteris 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 reallyneed to do is to use a ContentControlto host your UI.

我认为您的主要问题是 aContentPresenter仅在控件模板中使用。你不能只是把它贴在一个窗口中并期望它显示窗口的内容。我相信您真正需要做的是使用ContentControl来托管您的 UI。

By binding your model to the Contentproperty 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.

通过将您的模型绑定到Content该控件的属性,您可以设置包含该模型的预期视图的 DataTemplates。我给你一个简短的例子。请注意,这可能与您的设计不符,但它展示了这一切是如何结合在一起的。

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

首先,对于每个视图,创建一个模型(或 ViewModel)来管理该视图的数据(和交互)。

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

接下来,定义要在 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

接下来,在您的窗口中,添加 ContentControl 和 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 Dialogmodel.

最后将 Window 的 DataContext 设置为您的Dialog模型。

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 DataTemplateSelectorof the ContentControlsearches resources for a DataTemplatewhose DataTypeis set to typeof(Dialog)
  5. It finds this DataTemplate within the Window's Resources
  6. The content of the DataTemplate is loadedand added as a visual child of the ContentControl
  1. 您的窗口已创建。
  2. 在 DataContext 上设置了 Dialog 控件的实例。
  3. ContentControl 上的绑定已更新
  4. 默认DataTemplateSelector的的ContentControl搜索资源的DataTemplate,其DataType设置为typeof(Dialog)
  5. 它在窗口的资源中找到这个 DataTemplate
  6. DataTemplate 的内容被加载并添加为ContentControl

Any time the Contentof the ContentControlchanges, 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.

任何时间ContentContentControl变化,同样的过程重复。因此,您可以拥有许多不同的模型,每个模型都有不同的 DataTemplate,其中包含不同的 UserControl,并且每次更新 ContentControl 上的绑定时,您都会看到预期的视图。

With MVVM, you would bind a property of your ViewModel to the Contentproperty (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 Contentproperty becomes the DataContextof the immediate child of the ContentControl. Similar to how each ItemsSourcewithin an ItemsControlis the DataContextof the visual tree defined within the ItemTemplate.

使用 MVVM,您可以将 ViewModel 的Content属性绑定到该属性(称为 Current 或其他名称),然后根据 ViewModel 的当前状态将属性中的模型切换为预期值。请注意,在 ContentControl 中,设置为该Content属性的任何内容都将成为DataContextContentControl 的直接子项的 。方式类似,每个ItemsSourceItemsControlDataContext内定义的可视化树ItemTemplate

回答by 17 of 26

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.

我在这里隐藏了很多关于 OK 和 Cancel 的 view-viewmodel 交互的细节,但只要你有一个 DataTemplate 设置,那么这应该在窗口内呈现你的视图。

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

我在应用程序的资源字典中定义了我的 viewmodel-view 数据模板:

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