C# 如何以MVVM方式显示从外部程序集动态加载的UserControl

C# 如何以MVVM方式显示从外部程序集动态加载的UserControl,c#,wpf,mvvm,user-controls,C#,Wpf,Mvvm,User Controls,我正在开发一个WPF MVVM应用程序 MainWindow VM加载包含UserControl及其ViewModel的目标外部程序集 我想在主窗口视图中显示此UserControl 我认为我应该使用DataTemplates,但我不明白如何使它们与动态加载的类型一起工作。我没有代码可以显示,因为我不知道如何继续,任何建议都将不胜感激 编辑:下面是用于从程序集加载UC和VM的代码 Assembly assembly = Assembly.LoadFile(testProgramPath); va

我正在开发一个WPF MVVM应用程序

MainWindow VM加载包含UserControl及其ViewModel的目标外部程序集

我想在主窗口视图中显示此UserControl

我认为我应该使用DataTemplates,但我不明白如何使它们与动态加载的类型一起工作。我没有代码可以显示,因为我不知道如何继续,任何建议都将不胜感激

编辑:下面是用于从程序集加载UC和VM的代码

Assembly assembly = Assembly.LoadFile(testProgramPath);
var publicTypes = assembly.GetTypes().Where(t => t.IsPublic).ToArray();
TestProgramUserControl = publicTypes.Single(t => t.BaseType.FullName == "System.Windows.Controls.UserControl");
TestProgramUserControlViewModel = publicTypes.Single(t => t.GetCustomAttribute<TestProgramUserControlViewModelAttribute>() != null);
Assembly=Assembly.LoadFile(testProgramPath);
var publicTypes=assembly.GetTypes().Where(t=>t.IsPublic.ToArray();
TestProgramUserControl=publicTypes.Single(t=>t.BaseType.FullName==“System.Windows.Controls.UserControl”);
TestProgramUserControlViewModel=publicTypes.Single(t=>t.GetCustomAttribute()!=null);

我不能对UC或其VM做任何假设,我想在我的主窗口中显示它,无论它包含什么或做什么。然后,它将有责任通过适当的信息与合适的接收者进行沟通。

我的建议有点长,需要评论

既然你“不知道”怎么做,这里有一些建议给你指出正确的方向

托管可扩展性框架是为动态发现而设计的,用于按照您描述的方式扩展应用程序。他们为你做的

除了将视图和viewmodel放在这个程序集中,我还建议在其中放一个datatemplating resourcedictionary。可以使用此选项将视图类型与viewmodel类型关联。 您可以使用mef或仅使用命名约定来定义此资源字典是什么

要使mef能够发现资源字典,您需要为其添加代码隐藏类。然后,您可以将正确的属性应用于该属性,例如:

[Export(typeof(ResourceDictionary))]
public partial class ExternalDataTemplateResourceDictionary : ResourceDictionary
{
    public ExternalDataTemplateResourceDictionary ()
    {
        InitializeComponent();
    }
 }
要将该类连接到resourcedictionary,您可以使用类似于windows或usercontrols中的机制。在其开始标记中使用x:Class:

<ResourceDictionary      
       ....
       x:Class="YourProject.ExternalDataTemplateResourceDictionary "

多亏了这里的建议,在WPF聊天中,我解决了以下问题

我添加了一个约束:我的外部程序集只能包含一个UserControl,并且该用户控件必须将DataTemplate定义为具有固定名称的资源。 我的主VM从外部UC获得唯一具有上述固定名称的资源。 我的主视图将此DataTemplate用作ContentPresenter的ContentTemplate

外部用户控制的一些简化代码:

<UserControl xmlns:local="clr-namespace:MyNamespace">
    <UserControl.Resources>
        <ResourceDictionary>
            <DataTemplate x:Key="FixedKeyTemplate"
                          DataType="{x:Type local:MyOuterViewModel}">
                <StackPanel>
                    ...
                </StackPanel>
            </DataTemplate>
        </ResourceDictionary>
    </UserControl.Resources>
</UserControl>

...
主视图模型:

Assembly assembly = Assembly.LoadFile(testProgramPath);
var publicTypes = assembly.GetTypes().Where(t => t.IsPublic).ToArray();

Type userControlType = publicTypes.Single(t => t.BaseType.FullName == "System.Windows.Controls.UserControl");
UserControl userControlView = Activator.CreateInstance(userControlType) as UserControl;
DataTemplate userControlDataTemplate = userControlView.Resources["TestProgramGUIDataTemplate"] as DataTemplate;

Type userControlViewModelType = publicTypes.Single(t => t.GetCustomAttribute<UserControlViewModelCustomAttribute>() != null);
object userControlViewModel = Activator.CreateInstance(userControlViewModelType);
Assembly=Assembly.LoadFile(testProgramPath);
var publicTypes=assembly.GetTypes().Where(t=>t.IsPublic.ToArray();
类型userControlType=publicTypes.Single(t=>t.BaseType.FullName==“System.Windows.Controls.UserControl”);
UserControl userControlView=Activator.CreateInstance(userControlType)作为UserControl;
DataTemplate userControlDataTemplate=userControlView.Resources[“TestProgramGUIDataTemplate”]作为DataTemplate;
类型userControlViewModelType=publicTypes.Single(t=>t.GetCustomAttribute()!=null);
对象userControlViewModel=Activator.CreateInstance(userControlViewModelType);
主要观点:

<ContentPresenter Content="{Binding UserControlViewModel}"
                  ContentTemplate="{Binding Path=DataContext.UserControlTemplate,
                                            RelativeSource={RelativeSource Mode=FindAncestor,
                                                                           AncestorType={x:Type Window}}}"/>


@Andy suggestion更“专业”,但就我控制整个应用程序而言,而且我也是唯一的用户,我认为我可以对这个更简单的解决方案感到满意。

这是否回答了您的问题@Sinatr否,因为汇编在编译时是未知的。您能说明如何加载汇编、如何获取类型以及您到底想要什么吗?不清楚如何显示
UserControl
,但如果在该程序集中定义了数据模板(以显示特定类型),则只需加载该数据模板并将某些
ContentControl.Content
的实例设置为该动态类型的实例。@grandangelo:这与MVVM有何关系?若您有一个视图类型和一个视图模型类型,您将创建这两个类型的实例,并将视图实例的
DataContext
设置为视图模型的实例。@mm8与MVVM相关,因为我谈论的是视图模型和视图,我希望避免在代码隐藏中使用技巧。