C# 如何在WPF窗口上动态创建用户控件?

C# 如何在WPF窗口上动态创建用户控件?,c#,wpf,xaml,mvvm,user-controls,C#,Wpf,Xaml,Mvvm,User Controls,我现在正在和WPF合作。在将三种非常相似的形式合并为一种形式的过程中,我提出了一个问题。我写的代码很有效,但似乎远不是最好的解决方案,所以我想我应该向更广泛的受众寻求反馈和/或更好的解决方案 一些背景 这三种表单共享大量XAML和代码,但每种表单中都有不同的部分。我以一种形式保留了所有共享代码,并将不同的部分拆分为UserControl,目的是在运行时将其中一个动态加载到容器中。我们使用的是MVVM,因此表单和新的UserControls都有一个ViewModel。当然,表单的ViewModel

我现在正在和WPF合作。在将三种非常相似的形式合并为一种形式的过程中,我提出了一个问题。我写的代码很有效,但似乎远不是最好的解决方案,所以我想我应该向更广泛的受众寻求反馈和/或更好的解决方案

一些背景
这三种表单共享大量XAML和代码,但每种表单中都有不同的部分。我以一种形式保留了所有共享代码,并将不同的部分拆分为UserControl,目的是在运行时将其中一个动态加载到容器中。我们使用的是MVVM,因此表单和新的UserControls都有一个ViewModel。当然,表单的ViewModel充当父对象,并将新UserControls的ViewModels包含为子对象

问题本身
最初,我使用带有DataTemplateSelector的ContentControl从许多DataTemplates中进行选择,每个DataTemplates都包含一个UserControl。DataTemplateSelector中使用父视图模型中绑定到ContentControl的Content属性的属性来选择要使用的DataTemplate。由于我不太喜欢设置Content属性,我转而在ContentControl上使用带有DataTriggers的样式,执行几乎相同的任务。但是,我需要能够遍历逻辑树(如果您想知道的话,用于错误检查),并且使用这两种方法设置ContentTemplate似乎不允许我在加载ContentControl后继续沿着逻辑树进入UserControl。UserControl在容器中可见,并且通过其DataTemplate定义具有与其关联的正确ViewModel,但是ContentControl没有逻辑子级,因为Content属性为null。因此,我回过头来看的解决方案是检查表单构造函数中父视图模型的相关属性,并将其中一个UserControl显式实例化为ContentControl的Content属性。完成后,我可以将逻辑树遍历到UserControl中。看来一定有比这更好的方法,也许是在XAML中实现这一切的方法

所以…

有没有更好的方法来动态选择和实例化我的一个用户控件?我将表单中不同的部分拆分为UserControls的基本技术听起来合乎逻辑吗?这似乎是一个相当普遍的地方,重新使用一个窗口,但改变了它的某些部分,但我在谷歌的旅行中没有发现太多。也许我找的地方不对…

我想你应该在
可视化树上查看内容,而不是
逻辑树

另外,我无法从你上面的问题判断,但听起来你可能在寻找你的内容模板。如果是这样的话,它将不起作用,因为它是一个模板,所以它实际上不包含内容。这就像看着饼干切割机寻找饼干一样

另外,我更喜欢使用DataTemplates而不是DataTriggers。您也不需要DataTemplateSelector

在我的ParentViewModel中,我将具有如下属性:

private ViewModelBase _currentContent;
public ViewModelBase CurrentContent 
{
    get {return _currentContent;}
    set
    {
        if (value != _currentContent)
        {
            _currentContent = value;
            OnPropertyChanged("CurrentContent");
        }
    }
}
在ParentViewModel的XAML中,我会有如下内容

<ContentControl Content="{Binding CurrentContent}" />

然后,我将为不同的子viewmodel类型定义数据模板

<DataTemplate DataType="{x:Type local:SubViewModelA}">
    <local:ViewA />
</DataTemplate>
<DataTemplate DataType="{x:Type local:SubViewModelB}" />
    <local:ViewB />
</DataTemplate>
<DataTemplate DataType="{x:Type local:SubViewModelC}" />
    <local:ViewC />
</DataTemplate>


要切换内容,我需要将master的
CurrentContent
属性更改为应该显示的子视图模型

以正确的方式创建用户控件。我怀疑你做的不对的是遍历逻辑树。如果你不需要这么做,你也不需要担心剩下的事情。所以也许我们应该解决这个问题。第一个想法是最好的。我使用了
DataTemplateSelector
类,它支持在运行时切换视图,并且在一些更改后可以在Silverlight中工作。嗨,Rachel,谢谢你。在DataTemplate上添加数据类型非常简洁,并将子viewmodel牢牢地置于父视图的控制之下。我很喜欢。至于遍历逻辑树,我们可能需要查看可视化树。我已经消除了从外部进入UserControl的需要(我现在从UserControl内部调用所需的函数)。它工作得很好。我们将在某个时候回顾该过程,以便该部分可能很快被更好的部分替换。