c# - 如何以 MVVM 方式显示从外部程序集动态加载的 UserControl
问题描述
我正在开发一个 WPF MVVM 应用程序。
MainWindow VM 加载包含 UserControl 及其 ViewModel 的目标外部程序集。
我想在我的 MainWindow 视图中显示这个 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);
我不能对 UC 或其 VM 做出任何假设,我想在我的 MainWindow 中显示它包含或执行的任何内容。然后,它有责任通过适当的消息传递与合适的接收者进行沟通。
解决方案
感谢这里的建议,以及在 SO WPF 聊天中,我解决了我的问题如下。
我添加了一个约束:我的外部程序集只能包含一个 UserControl,并且这个用户控件必须将一个 DataTemplate 定义为具有固定名称的资源。我的主虚拟机从外部 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);
主视图:
<ContentPresenter Content="{Binding UserControlViewModel}"
ContentTemplate="{Binding Path=DataContext.UserControlTemplate,
RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType={x:Type Window}}}"/>
@Andy 的建议更“专业”,但就我控制整个应用程序而言,我也是唯一的用户,我想我可以对这个更简单的解决方案感到满意。
推荐阅读
- angular - 客户端上的Angular SSR双重加载
- html - Flex 行的高度加起来为父引导程序 4
- node.js - 使用 CodeDeploy、Parameter Store 和 PM2 设置 EC2 环境变量
- javascript - 如何使用 Chai 检查值是否为正数?
- python - for循环没有被执行python
- python-3.x - 如何在执行用户命令后向机器人发送的消息中添加反应表情符号?
- javascript - 模态体在按钮单击时消失
- nlp - 为什么BERT NSP头部线性层有两个输出?
- unity3d - Unity 不使用 iOS Resolver 生成 xcworkspace、Podfile - macOS Catalina
- python - 是什么导致 Google Sheets API Traceback/Refresh 错误?