WPF Prism 复合命令与模块化管理 电脑版发表于:2025/5/8 15:00  ># WPF Prism 复合命令与模块化管理 [TOC] Prism 中的 CompositeCommand 示例 ------------ tn2>CompositeCommand 是 Prism 框架中用于组合多个子命令(DelegateCommand 实例)的类。它允许你将多个命令表示为单个命令,或者在需要时调用多个命令来实现一个逻辑命令。 ### 示例代码 tn2>这里做一个简单的示例,注册父窗体中的按钮命令,让子窗口进行调用。 首先我们定义一个复合命令类,并在`App.xaml.cs`中注册单例全局。 ```csharp namespace LearningRegionPrism.Commands { public class MyApplicationCommands { private CompositeCommand _saveCommand = new CompositeCommand(); public CompositeCommand SaveCommand { get => _saveCommand; } } } ``` ```csharp public partial class App : PrismApplication { protected override Window CreateShell() { return Container.Resolve<MainWindowView>(); } protected override void RegisterTypes(IContainerRegistry containerRegistry) { containerRegistry.RegisterForNavigation<TestRegionWindowView>(); containerRegistry.RegisterForNavigation<MMView>(); // 在这里注册 containerRegistry.RegisterSingleton<MyApplicationCommands>(); } protected override void ConfigureRegionAdapterMappings(RegionAdapterMappings regionAdapterMappings) { base.ConfigureRegionAdapterMappings(regionAdapterMappings); regionAdapterMappings.RegisterMapping<Canvas>(Container.Resolve<CanvasRegionAdapter>()); } } ``` tn2>然后我们在`MainWindowView.xaml`中添加一个`TextBlock`标签,用于绑定`MainWindowViewModel`中的`Msg`。 ```xml <TextBlock Text="{Binding Msg}" Grid.ColumnSpan="2" VerticalAlignment="Center"/> ``` tn2>然后我们在`MainWindowViewModel`类中定义`Msg`属性,并且添加一个`UpdateMessageCommand`命令并将其在构造函数中进行注册到复合命令。 ```csharp public class MainWindowViewModel : BindableBase { private string _Msg = "Bob 子窗口"; public string Msg { get { return _Msg; } set { SetProperty(ref _Msg, value); } } public MainWindowViewModel(MyApplicationCommands commands) { // 注册 commands.SaveCommand.RegisterCommand(UpdateMessageCommand); } public ICommand UpdateMessageCommand { get => new DelegateCommand(() => { Msg = "从子窗体进行了修改"; }); } } ``` tn2>然后我们在`MMView.xaml`中添加一个按钮并绑定`ParentBtnCommand`命令。 ```xml <Button Content="Exect Parent Command" Command="{Binding ParentBtnCommand}"/> ``` tn2>在`MMViewModel`中,定义一个复合命令属性,然后从`MyApplicationCommands`中获取属性,进行调用尝试。 ```csharp public CompositeCommand ParentBtnCommand { get; private set; } public MMViewModel(IRegionNavigationService regionNavigationService,MyApplicationCommands commands) { ParentBtnCommand = commands.SaveCommand; } ```    tn2>我们可以看到它对父窗口进行修改。 模块化管理 ------------ tn2>在 Prism 框架中,模块化开发是一种核心设计理念,它通过将应用程序划分为多个独立的模块,帮助开发者更好地组织代码,实现松耦合的架构设计。本文将通过一个简单的示例,详细介绍如何在 Prism 中实现模块化开发。 ### 简单示例 tn2>打开 Visual Studio,创建一个新的 WPF 用户控件库项目,命名为 `LearningPrismControlLibrary`。 并添加上`Prism`相关包。  ```xml <ItemGroup> <PackageReference Include="Prism.Core" Version="9.0.537" /> <PackageReference Include="Prism.Unity" Version="9.0.537" /> <PackageReference Include="Prism.Wpf" Version="9.0.537" /> </ItemGroup> ``` tn2>创建一个简单的视图`ViewA`和`ViewAViewModel`。 ```xml <UserControl x:Class="LearningPrismControlLibrary.Views.ViewA" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:LearningPrismControlLibrary.Views" mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800"> <Grid> <TextBlock Text="{Binding Msg}"/> </Grid> </UserControl> ``` ```csharp public class ViewAViewModel : BindableBase { private string _Msg = "100"; public string Msg { get { return _Msg; } set { SetProperty(ref _Msg, value); } } } ``` tn2>接下来我们定义一下我们的`SubModule`模块类,并将我们的`ViewA`注册到`SubModule`中。 ```csharp namespace LearningPrismControlLibrary { public class SubModule : IModule { public void OnInitialized(IContainerProvider containerProvider) { } public void RegisterTypes(IContainerRegistry containerRegistry) { containerRegistry.RegisterForNavigation<ViewA>(); } } } ``` tn2>在我们`LearningRegionPrism`项目中添加相关的用户控件类库,然后在`App.xaml.cs`中添加我们的模块。 ```csharp protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog) { moduleCatalog.AddModule<SubModule>(); } ``` tn2>在`MainWindowView`中我们在构造中显示并注册`ViewA`视图到`MainContent`区域中。 ```csharp public MainWindowView(IRegionManager regionManager) { InitializeComponent(); regionManager.RegisterViewWithRegion<ViewA>("MainContent"); } ``` tn2>然后我们运行测试一下,发现没有问题。  ### 按需加载模块的方式 tn2>当我们需要`ViewA`的时候加载该模块,不需要则可以不用加载。 可以按照如下方式操作,首先修改`ConfigureModuleCatalog`方法: ```csharp protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog) { // 名称加载 // moduleCatalog.AddModule<SubModule>(); // 第二种加载方式 var typename = typeof(SubModule); moduleCatalog.AddModule(new ModuleInfo() { ModuleName = "hello", // 设置模块类型为 SubModule 类的程序集限定名,ModuleType 指定模块的完整类型信息,包括命名空间和程序集名称,Prism 根据此信息来实例化模块 ModuleType = typename.AssemblyQualifiedName, // 设置模块的初始化模式为按需加载,InitializationMode.OnDemand 表示模块不会在应用程序启动时自动初始化,而是在需要时才进行初始化,这样可以提高应用程序的启动性能 InitializationMode = InitializationMode.OnDemand }); } ``` tn2>在`MainWindowView`中注释掉注册的视图的代码。 ```csharp //regionManager.RegisterViewWithRegion<ViewA>("MainContent"); ``` tn2>在`MainWindowView.xaml`中我们添加一个新的按钮,当点击时加载模块然后显示`ViewA`区域。 ```xml <Button Content="Module Button" Command="{Binding ModuleBtnCommand}" CommandParameter="ViewA"/> ``` ```csharp [Dependency] public IModuleManager moduleManager { get; set; } public ICommand ModuleBtnCommand { get => new DelegateCommand<string>((x) => { moduleManager.LoadModule("hello"); regionManager.RequestNavigate("MainContent",x); }); } ```   ### 配置文件添加模块 tn2>添加`App.config`配置文件,并进行如下配置:  ```xml <?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <section name="modules" type="Prism.Modularity.ModulesConfigurationSection, Prism.Wpf"/> </configSections> <modules> <module assemblyFile="LearningPrismControlLibrary" moduleType="LearningPrismControlLibrary.SubModule, LearningPrismControlLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" moduleName="hello" startupLoaded="false"> </module> </modules> </configuration> ``` tn2>修改`App.xaml.cs`,模块的创建改为配置文件创建。 ```csharp protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog) { // 名称加载 //moduleCatalog.AddModule<SubModule>(); // 第二种加载方式 //var typename = typeof(SubModule); //moduleCatalog.AddModule(new ModuleInfo() //{ // ModuleName = "hello", // // 设置模块类型为 SubModule 类的程序集限定名,ModuleType 指定模块的完整类型信息,包括命名空间和程序集名称,Prism 根据此信息来实例化模块 // ModuleType = typename.AssemblyQualifiedName, // // 设置模块的初始化模式为按需加载,InitializationMode.OnDemand 表示模块不会在应用程序启动时自动初始化,而是在需要时才进行初始化,这样可以提高应用程序的启动性能 // InitializationMode = InitializationMode.OnDemand //}); // 配置文件添加模块 } protected override IModuleCatalog CreateModuleCatalog() { return new ConfigurationModuleCatalog(); } ``` 