tnblog
首页
视频
资源
登录

WPF Prism 复合命令与模块化管理

280人阅读 2025/5/8 15:00 总访问:3660129 评论:0 收藏:0 手机
分类: .net后台框架

WPF Prism 复合命令与模块化管理

Prism 中的 CompositeCommand 示例


CompositeCommand 是 Prism 框架中用于组合多个子命令(DelegateCommand 实例)的类。它允许你将多个命令表示为单个命令,或者在需要时调用多个命令来实现一个逻辑命令。

示例代码


这里做一个简单的示例,注册父窗体中的按钮命令,让子窗口进行调用。
首先我们定义一个复合命令类,并在App.xaml.cs中注册单例全局。

  1. namespace LearningRegionPrism.Commands
  2. {
  3. public class MyApplicationCommands
  4. {
  5. private CompositeCommand _saveCommand = new CompositeCommand();
  6. public CompositeCommand SaveCommand
  7. {
  8. get => _saveCommand;
  9. }
  10. }
  11. }
  1. public partial class App : PrismApplication
  2. {
  3. protected override Window CreateShell()
  4. {
  5. return Container.Resolve<MainWindowView>();
  6. }
  7. protected override void RegisterTypes(IContainerRegistry containerRegistry)
  8. {
  9. containerRegistry.RegisterForNavigation<TestRegionWindowView>();
  10. containerRegistry.RegisterForNavigation<MMView>();
  11. // 在这里注册
  12. containerRegistry.RegisterSingleton<MyApplicationCommands>();
  13. }
  14. protected override void ConfigureRegionAdapterMappings(RegionAdapterMappings regionAdapterMappings)
  15. {
  16. base.ConfigureRegionAdapterMappings(regionAdapterMappings);
  17. regionAdapterMappings.RegisterMapping<Canvas>(Container.Resolve<CanvasRegionAdapter>());
  18. }
  19. }


然后我们在MainWindowView.xaml中添加一个TextBlock标签,用于绑定MainWindowViewModel中的Msg

  1. <TextBlock Text="{Binding Msg}" Grid.ColumnSpan="2" VerticalAlignment="Center"/>


然后我们在MainWindowViewModel类中定义Msg属性,并且添加一个UpdateMessageCommand命令并将其在构造函数中进行注册到复合命令。

  1. public class MainWindowViewModel : BindableBase
  2. {
  3. private string _Msg = "Bob 子窗口";
  4. public string Msg
  5. {
  6. get { return _Msg; }
  7. set { SetProperty(ref _Msg, value); }
  8. }
  9. public MainWindowViewModel(MyApplicationCommands commands)
  10. {
  11. // 注册
  12. commands.SaveCommand.RegisterCommand(UpdateMessageCommand);
  13. }
  14. public ICommand UpdateMessageCommand
  15. {
  16. get => new DelegateCommand(() =>
  17. {
  18. Msg = "从子窗体进行了修改";
  19. });
  20. }
  21. }


然后我们在MMView.xaml中添加一个按钮并绑定ParentBtnCommand命令。

  1. <Button Content="Exect Parent Command" Command="{Binding ParentBtnCommand}"/>


MMViewModel中,定义一个复合命令属性,然后从MyApplicationCommands中获取属性,进行调用尝试。

  1. public CompositeCommand ParentBtnCommand { get; private set; }
  2. public MMViewModel(IRegionNavigationService regionNavigationService,MyApplicationCommands commands)
  3. {
  4. ParentBtnCommand = commands.SaveCommand;
  5. }


我们可以看到它对父窗口进行修改。

模块化管理


在 Prism 框架中,模块化开发是一种核心设计理念,它通过将应用程序划分为多个独立的模块,帮助开发者更好地组织代码,实现松耦合的架构设计。本文将通过一个简单的示例,详细介绍如何在 Prism 中实现模块化开发。

简单示例


打开 Visual Studio,创建一个新的 WPF 用户控件库项目,命名为 LearningPrismControlLibrary
并添加上Prism相关包。

  1. <ItemGroup>
  2. <PackageReference Include="Prism.Core" Version="9.0.537" />
  3. <PackageReference Include="Prism.Unity" Version="9.0.537" />
  4. <PackageReference Include="Prism.Wpf" Version="9.0.537" />
  5. </ItemGroup>


创建一个简单的视图ViewAViewAViewModel

  1. <UserControl x:Class="LearningPrismControlLibrary.Views.ViewA"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  5. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  6. xmlns:local="clr-namespace:LearningPrismControlLibrary.Views"
  7. mc:Ignorable="d"
  8. d:DesignHeight="450" d:DesignWidth="800">
  9. <Grid>
  10. <TextBlock Text="{Binding Msg}"/>
  11. </Grid>
  12. </UserControl>
  1. public class ViewAViewModel : BindableBase
  2. {
  3. private string _Msg = "100";
  4. public string Msg
  5. {
  6. get { return _Msg; }
  7. set { SetProperty(ref _Msg, value); }
  8. }
  9. }


接下来我们定义一下我们的SubModule模块类,并将我们的ViewA注册到SubModule中。

  1. namespace LearningPrismControlLibrary
  2. {
  3. public class SubModule : IModule
  4. {
  5. public void OnInitialized(IContainerProvider containerProvider)
  6. {
  7. }
  8. public void RegisterTypes(IContainerRegistry containerRegistry)
  9. {
  10. containerRegistry.RegisterForNavigation<ViewA>();
  11. }
  12. }
  13. }


在我们LearningRegionPrism项目中添加相关的用户控件类库,然后在App.xaml.cs中添加我们的模块。

  1. protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog)
  2. {
  3. moduleCatalog.AddModule<SubModule>();
  4. }


MainWindowView中我们在构造中显示并注册ViewA视图到MainContent区域中。

  1. public MainWindowView(IRegionManager regionManager)
  2. {
  3. InitializeComponent();
  4. regionManager.RegisterViewWithRegion<ViewA>("MainContent");
  5. }


然后我们运行测试一下,发现没有问题。

按需加载模块的方式


当我们需要ViewA的时候加载该模块,不需要则可以不用加载。
可以按照如下方式操作,首先修改ConfigureModuleCatalog方法:

  1. protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog)
  2. {
  3. // 名称加载
  4. // moduleCatalog.AddModule<SubModule>();
  5. // 第二种加载方式
  6. var typename = typeof(SubModule);
  7. moduleCatalog.AddModule(new ModuleInfo() {
  8. ModuleName = "hello",
  9. // 设置模块类型为 SubModule 类的程序集限定名,ModuleType 指定模块的完整类型信息,包括命名空间和程序集名称,Prism 根据此信息来实例化模块
  10. ModuleType = typename.AssemblyQualifiedName,
  11. // 设置模块的初始化模式为按需加载,InitializationMode.OnDemand 表示模块不会在应用程序启动时自动初始化,而是在需要时才进行初始化,这样可以提高应用程序的启动性能
  12. InitializationMode = InitializationMode.OnDemand
  13. });
  14. }


MainWindowView中注释掉注册的视图的代码。

  1. //regionManager.RegisterViewWithRegion<ViewA>("MainContent");


MainWindowView.xaml中我们添加一个新的按钮,当点击时加载模块然后显示ViewA区域。

  1. <Button Content="Module Button" Command="{Binding ModuleBtnCommand}" CommandParameter="ViewA"/>
  1. [Dependency]
  2. public IModuleManager moduleManager { get; set; }
  3. public ICommand ModuleBtnCommand
  4. {
  5. get => new DelegateCommand<string>((x) =>
  6. {
  7. moduleManager.LoadModule("hello");
  8. regionManager.RequestNavigate("MainContent",x);
  9. });
  10. }

配置文件添加模块


添加App.config配置文件,并进行如下配置:

  1. <?xml version="1.0" encoding="utf-8" ?>
  2. <configuration>
  3. <configSections>
  4. <section name="modules" type="Prism.Modularity.ModulesConfigurationSection, Prism.Wpf"/>
  5. </configSections>
  6. <modules>
  7. <module
  8. assemblyFile="LearningPrismControlLibrary"
  9. moduleType="LearningPrismControlLibrary.SubModule, LearningPrismControlLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
  10. moduleName="hello" startupLoaded="false">
  11. </module>
  12. </modules>
  13. </configuration>


修改App.xaml.cs,模块的创建改为配置文件创建。

  1. protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog)
  2. {
  3. // 名称加载
  4. //moduleCatalog.AddModule<SubModule>();
  5. // 第二种加载方式
  6. //var typename = typeof(SubModule);
  7. //moduleCatalog.AddModule(new ModuleInfo()
  8. //{
  9. // ModuleName = "hello",
  10. // // 设置模块类型为 SubModule 类的程序集限定名,ModuleType 指定模块的完整类型信息,包括命名空间和程序集名称,Prism 根据此信息来实例化模块
  11. // ModuleType = typename.AssemblyQualifiedName,
  12. // // 设置模块的初始化模式为按需加载,InitializationMode.OnDemand 表示模块不会在应用程序启动时自动初始化,而是在需要时才进行初始化,这样可以提高应用程序的启动性能
  13. // InitializationMode = InitializationMode.OnDemand
  14. //});
  15. // 配置文件添加模块
  16. }
  17. protected override IModuleCatalog CreateModuleCatalog()
  18. {
  19. return new ConfigurationModuleCatalog();
  20. }

自定义配置文件添加模块


首先我们创建一个ModuleConfigs文件夹,在下面创建一个我们自定义的ModuleConfig.xml模块配置文件,文件内容如下:

  1. <?xml version="1.0" encoding="utf-8" ?>
  2. <m:ModuleCatalog xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. xmlns:m="clr-namespace:Prism.Modularity;assembly=Prism.Wpf">
  5. <m:ModuleInfo ModuleName="hello"
  6. ModuleType="LearningPrismControlLibrary.SubModule, LearningPrismControlLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
  7. InitializationMode="OnDemand"
  8. />
  9. </m:ModuleCatalog>

注意需要将这个文件设置为资源类型的文件。


然后我们修改App.xaml.cs下的CreateModuleCatalog方法。

  1. protected override IModuleCatalog CreateModuleCatalog()
  2. {
  3. //return new ConfigurationModuleCatalog();
  4. var url = new Uri("/LearningRegionPrism;component/ModuleConfigs/ModuleConfig.xml"
  5. , UriKind.RelativeOrAbsolute);
  6. // 第二种方式自定义配置文件加载方式
  7. return new XamlModuleCatalog(url);
  8. }

扫描目录加载模块


通过扫描某个目录进行加载模块。
首先我们需要给我们的模块添加上模块名称。

  1. namespace LearningPrismControlLibrary
  2. {
  3. [Module(ModuleName = "hello",OnDemand =true)]
  4. public class SubModule : IModule
  5. {
  6. public void OnInitialized(IContainerProvider containerProvider)
  7. {
  8. }
  9. public void RegisterTypes(IContainerRegistry containerRegistry)
  10. {
  11. containerRegistry.RegisterForNavigation<ViewA>();
  12. }
  13. }
  14. }


然后我们修改App.xaml.cs下的CreateModuleCatalog方法,使用目录扫描的方式进行加载模块,这里我们扫描Mods文件夹下面的模块。

  1. protected override IModuleCatalog CreateModuleCatalog()
  2. {
  3. //return new ConfigurationModuleCatalog();
  4. //var url = new Uri("/LearningRegionPrism;component/ModuleConfigs/ModuleConfig.xml"
  5. // , UriKind.RelativeOrAbsolute);
  6. //// 第二种方式自定义配置文件加载方式
  7. //return new XamlModuleCatalog(url);
  8. // 第三种扫描目录的方式
  9. return new DirectoryModuleCatalog() { ModulePath = "./Mods" };
  10. }


然后我们重新生成我们的代码,然后在输出目录创建一个Mods文件夹,将我们的模块文件放在这个下面:


运行测试一下。


欢迎加群讨论技术,1群:677373950(满了,可以加,但通过不了),2群:656732739

评价

WPF Prism 框架:打造高效、可维护的 WPF 应用

WPF Prism 框架:打造高效、可维护的 WPF 应用[TOC] Prism 框架简介Prism 是一个用于构建松耦合、可维护且可测试的 XAML ...

WPF Prism 框架初始化

WPF Prism 框架初始化[TOC] 什么是 Prism Bootstrapper?Prism Bootstrapper 是一个抽象类,它定义了一个基本的启动序列,...

WPF Prism ViewModel的应用

WPF Prism ViewModel的应用[TOC] 在 WPF 开发中,Prism 是一个非常流行的框架,它基于 MVVM(Model-View-ViewModel)模式...

WPF Prism Dialog与Region

WPF Prism Dialog与Region[TOC] Prism框架中的Dialog子窗口处理在 WPF 应用程序开发中,对话框是一个常见的功能需求,无论...
这一世以无限游戏为使命!
排名
2
文章
657
粉丝
44
评论
93
docker中Sware集群与service
尘叶心繁 : 想学呀!我教你呀
一个bug让程序员走上法庭 索赔金额达400亿日元
叼着奶瓶逛酒吧 : 所以说做程序员也要懂点法律知识
.net core 塑形资源
剑轩 : 收藏收藏
映射AutoMapper
剑轩 : 好是好,这个对效率影响大不大哇,效率高不高
ASP.NET Core 服务注册生命周期
剑轩 : http://www.tnblog.net/aojiancc2/article/details/167
ICP备案 :渝ICP备18016597号-1
网站信息:2018-2025TNBLOG.NET
技术交流:群号656732739
联系我们:contact@tnblog.net
公网安备:50010702506256
欢迎加群交流技术