C# 如何以MVVM方式显示从外部程序集动态加载的UserControl
我正在开发一个WPF MVVM应用程序 MainWindow VM加载包含UserControl及其ViewModel的目标外部程序集 我想在主窗口视图中显示此UserControl 我认为我应该使用DataTemplates,但我不明白如何使它们与动态加载的类型一起工作。我没有代码可以显示,因为我不知道如何继续,任何建议都将不胜感激 编辑:下面是用于从程序集加载UC和VM的代码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
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相关,因为我谈论的是视图模型和视图,我希望避免在代码隐藏中使用技巧。