惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Webroot Blog
Webroot Blog
U
Unit 42
A
About on SuperTechFans
宝玉的分享
宝玉的分享
月光博客
月光博客
C
CERT Recently Published Vulnerability Notes
P
Privacy International News Feed
Microsoft Security Blog
Microsoft Security Blog
G
Google Developers Blog
P
Privacy & Cybersecurity Law Blog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
S
Securelist
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Spread Privacy
Spread Privacy
L
Lohrmann on Cybersecurity
Apple Machine Learning Research
Apple Machine Learning Research
K
Kaspersky official blog
Hugging Face - Blog
Hugging Face - Blog
B
Blog
I
Intezer
Last Week in AI
Last Week in AI
T
Threat Research - Cisco Blogs
V
V2EX
L
LangChain Blog
AI
AI
G
GRAHAM CLULEY
T
Tor Project blog
人人都是产品经理
人人都是产品经理
D
Docker
WordPress大学
WordPress大学
Google DeepMind News
Google DeepMind News
I
InfoQ
Y
Y Combinator Blog
C
Comments on: Blog
GbyAI
GbyAI
www.infosecurity-magazine.com
www.infosecurity-magazine.com
酷 壳 – CoolShell
酷 壳 – CoolShell
T
Tailwind CSS Blog
aimingoo的专栏
aimingoo的专栏
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
腾讯CDC
N
News and Events Feed by Topic
MyScale Blog
MyScale Blog
H
Help Net Security
Vercel News
Vercel News
T
Tenable Blog
博客园 - 三生石上(FineUI控件)
爱范儿
爱范儿

博客园 - zhaotianff

一文带你搞懂医疗器械设计开发全生命周期 Windows如何清除本机记录的git用户名和密码 HL7协议详解 医疗行业 GDT 数据格式详解 一文带你搞懂C# 异步编程(async/await)底层原理 如何在C#中使用Chromium headless(无头模式)浏览器 不同.NET版本中的WPF新增功能 如何在WPF中使用 Fluent 主题 Windows平台下的各种原生UI框架介绍 C#如何Hook托管函数 WinDbg 用户层调试进阶教程 Windows编程的一些基础理论 推荐一款优秀的Windows经典文件管理器项目-WinFile Windows如何阻止应用程序联网 如何在WPF中捕获窗口外的事件 如何查看Windows进程的启动来源 Visual Studio 2026新解决方案格式slnx详解 我的微软MVP申请通过了 WPF MVVM实战系列教程(八、Prism DialogService, 对话框服务) WPF 性能优化实战指南 WPF MVVM实战系列教程(六、Prism区域导航) WPF MVVM实战系列教程(五、Prism中的MVVM) WPF MVVM实战系列教程(四、Prism中的依赖注入) 微软 IDE 新纪元:Visual Studio 2026 初体验 Windows 7无法安装VMWare Tools的解决办法 WPF MVVM实战系列教程(三、创建Bootstrapper/启动器) WPF MVVM实战系列教程(二、使用Visual Studio 创建Prism项目) WPF MVVM实战系列教程(一、Prism框架介绍)
WPF MVVM实战系列教程(七、Prism模块化)
zhaotianff · 2026-01-27 · via 博客园 - zhaotianff

模块化基础

首先我们了解一下插件这个概念

插件(add-in,也称为plug-in)是应用程序能够动态发现、加载和使用的单独编译过的组件。

通常,应将应用程序设计成能使用插件,从而可在将来进行增强,而不必进行任何修改、重新编译以及重新测试。

插件还为针对特殊的市场或客户单独定制应用程序实例提供了灵活性。但使用插件模型最常见的原因是,允许第三方开发人员扩展应用程序的功能。

例如,AdobePhotoshop中的插件提供了大量图片处理效果,类似Camera Raw。Google Chrome中的插件提供了增强的Web 冲浪特性以及全新功能。对于这两种情况,插件都是由第三方开发人员创建的。

.NET提供了MAF和MEF两种框架可以实现插件化。

MAF:https://learn.microsoft.com/en-us/dotnet/desktop/wpf/app-development/wpf-add-ins-overview

MEF:https://learn.microsoft.com/zh-cn/dotnet/framework/mef/

Prism的模块化原理就类似插件模型。它也能够动态地发现、加载和使用单独编译的组件。

在前面介绍Prism框架时,提到模块化的作用。模块化拆分、隔离与复用,核心目标都是降低应用耦合度,提升可维护性。

模块化以后

1、每个模块负责特定功能(如用户管理、订单管理),实现 “高内聚、低耦合”,便于团队协作、维护和迭代。

2、模块之间可以做到低依赖(减少直接引用,通过依赖注入实现复用),单个模块可独立编译、测试,甚至在多个应用中复用。

3、最终都能将多个独立模块整合到同一个主应用中,形成完整的功能体系,而非零散的组件。

image

就拿医疗行业的软件来说,它可能会划分如上的模块。不同的模块可以单独开发,测试。最后再将它们一起”组装“到”外壳“上。

对于一些基础模块,通常会定义成公用模块。需要使用的子模块可以直接引用这些基础模块。

注意:这里我们的目的是做到模块间低依赖,而不是完全没有依赖。

但是Prism的模块化和插件化会有稍许区别

Prism模块化:

模块化是 “核心架构手段”,最终目的是 “大型应用的结构化拆分与管理”。

Prism 希望在应用开发初期,就将应用拆分为多个模块,每个模块遵循统一的规范(IModule),主应用通过明确配置加载模块,便于团队分工、版本控制和后期维护。

简单来说:Prism 的模块化是为了 “事前规划”。

插件化:

最终目的是 “可扩展性”(插件化)。

当主应用发布后,无需修改主程序代码、无需重新编译,只需将新的模块(插件)放入指定目录,主应用就能自动识别并加载该模块,实现功能扩展。

简单说:插件化是为了 “事后扩展”。

模块化原则 

有些小伙伴可能对这个模块的划分还存在一些困惑。

这里介绍 一下模块划分的原则 

1、高内聚:一个模块只负责完成单一且明确的业务功能,不包含无关逻辑。

2、低耦合:模块之间尽量减少直接依赖,禁止跨模块直接引用View、ViewModel 或内部业务类。

3、创建独立的基础设施类库(CommonInfrastructure 项目),该项目仅包含公共接口、枚举、实体(DTO/POCO,无业务逻辑)。

这个基础设备类库是模块间交互的核心

模块加载基础原理

在Prism中涉及两种模块化的加载,一种是配置式,一种是扫描式。

配置式是显式配置,也就是主动指定要加载的模块。扫描式是隐式配置,也就是对目录进行扫描,然后自动添加符合要求的模块。

模块加载这里主要用到的是.NET的反射机制。

假设我定义了一个IModule接口(仅演示用,所以未定义具体的接口函数)

1 public interface IModule
2 {
3 
4  
5 }

然后我定义了一个类库LibA,增加一个类ModuleAModule继承自IModule接口

1    public class ModuleAModule : IModule
2    {
3       
4    }

再定义一个类库LibB,增加一个类ModuleBModule

1  public class ModuleBModule
2 {
3   
4 }

image

当我们去扫描这两个dll,通过判断是否实现了IModule接口,就可以判断是否是我们定义的模块。

简易验证过程如下:

  • 第一步:通过Type.GetInterface(typeof(IModule).FullName)验证该类型是否实现了IModule
  • 第二步:验证该类型是否为class、是否非抽象(type.IsClass && !type.IsAbstract)。

示例代码如下:

 1 public List<Type> FindAllIModuleTypes(string moduleDirectory)
 2 {
 3     var moduleTypes = new List<Type>();
 4     var assemblyFiles = Directory.GetFiles(moduleDirectory, "*.dll", SearchOption.TopDirectoryOnly);
 5 
 6     foreach (var assemblyFile in assemblyFiles)
 7     {
 8         try
 9         {
10             // 1. 加载程序集
11             Assembly assembly = Assembly.LoadFrom(assemblyFile);
12 
13             // 2. 遍历程序集中的所有类型
14             foreach (Type type in assembly.GetTypes())
15             {
16                 // 3. 核心筛选:识别 IModule 实现类
17                 bool isValidModule = typeof(IModule).IsAssignableFrom(type) && // 实现 IModule
18                     type.IsClass && // 是类
19                     !type.IsAbstract; // 非抽象
20 
21                 if (isValidModule)
22                 {
23                     moduleTypes.Add(type);
24                 }
25             }
26         }
27         catch
28         {
29             // 跳过无法加载或无有效模块的程序集
30             continue;
31         }
32     }
33 
34     return moduleTypes;
35 }

Prism中的IModule接口

首先我们了解一下IModule接口,在Prism中,可以被加载的模块都需要实现Prism.Modularity.IModule接口。

IModule接口定义如下:

 1 //
 2 // 摘要:
 3 //     为Prism应用程序中部署的模块定义契约。
 4 public interface IModule
 5 {
 6     //
 7     // 摘要:
 8     //     用于向容器注册应用程序将使用的类型。
 9     void RegisterTypes(IContainerRegistry containerRegistry);
10 
11     //
12     // 摘要:
13     //     通知模块它已被初始化。
14     void OnInitialized(IContainerProvider containerProvider);
15 }

IModule提供了两个接口函数:RegisterTypesOnInitialized,可以把它理解为模块的Bootstrapper。 

如何创建Prism模块

这里我们以一个简易的信息登记功能为例,增加一个Register模块,一个ViewList模块,一个CommonModule公共模块

Register模块:登记Employee信息

ViewList模块:查看登记的Employee列表

CommonModule公共模块:定义Employee及通信事件

当在Register模块登记一个Employee后,通过ViewModel通信,将Employee添加到ViewList模块的列表中。

整体框架如下:

image

1、定义公用模块CommonModule

这个模块主要是用于定义Employee及通信事件。

SelectEmployeeEvent.cs

1  public class SelectEmployeeEvent : PubSubEvent<IEmployeeViewModel>
2  {
3  }

IEmployeeViewModel.cs

 1  public interface IEmployeeViewModel
 2  {
 3      int Id { get; set; }
 4 
 5      string Name { get; set; }
 6 
 7      string Phone { get; set; }
 8 
 9      void XXX();
10  }

2、创建类库工程Module.Register

image

3、增加一个模块类RegisterModule实现IModule接口

注意:模块类在命名时,尽量以Module结尾,而且放在项目的根目录下,这样方便后期区分和查找

image

RegisterModule.cs

 1  public class RegisterModule : Prism.Modularity.IModule
 2  {
 3      public void OnInitialized(IContainerProvider containerProvider)
 4      {
 5          
 6      }
 7 
 8      public void RegisterTypes(IContainerRegistry containerRegistry)
 9      {
10          
11      }
12  }

这样我们就拥有了一个可以被Prism识别的模块

接下来我们对这个模块进行完善 

4、添加View和ViewModel

注意:类库工程在添加View时,会找不到WPF项。

image

 需要修改项目工程文件,添加UseWPF

image

添加Views\Register.xaml

这个页面用于登记

 1  <Grid>
 2      <Grid.RowDefinitions>
 3          <RowDefinition/>
 4          <RowDefinition/>
 5          <RowDefinition/>
 6          <RowDefinition/>
 7      </Grid.RowDefinitions>
 8 
 9      <Grid.ColumnDefinitions>
10          <ColumnDefinition/>
11          <ColumnDefinition/>
12      </Grid.ColumnDefinitions>
13 
14      <Label Content="Id" HorizontalAlignment="Right" Margin="0,0,30,0" VerticalAlignment="Center"></Label>
15      <TextBox Grid.Row="0" Grid.Column="1" Margin="40,0" VerticalAlignment="Center"  Text="{Binding EmployeeViewModel.Id}"></TextBox>
16 
17      <Label Content="Name" Grid.Row="1" HorizontalAlignment="Right" Margin="0,0,30,0" VerticalAlignment="Center"></Label>
18      <TextBox Grid.Row="1" Grid.Column="1" Margin="40,0"  VerticalAlignment="Center"  Text="{Binding EmployeeViewModel.Name}"></TextBox>
19 
20      <Label Content="Phone" Grid.Row="2" HorizontalAlignment="Right" Margin="0,0,30,0" VerticalAlignment="Center"></Label>
21      <TextBox Grid.Row="2" Grid.Column="1" Margin="40,0"  VerticalAlignment="Center" Text="{Binding EmployeeViewModel.Phone}"></TextBox>
22 
23      <Button Content="登记" Width="88" Height="28" HorizontalAlignment="Center" VerticalAlignment="Center" Grid.Row="3" Grid.ColumnSpan="2" Command="{Binding RegisterCommand}"></Button>
24  </Grid>

添加ViewModels\RegisterViewModel.cs

 1   public class RegisterViewModel :BindableBase
 2   {
 3       private IEventAggregator eventAggregator;
 4 
 5       public DelegateCommand RegisterCommand { get; private set; }
 6  
 7       //EmployeeViewModel的定义请到文末示例代码中查看
 8       private EmployeeViewModel employeeViewModel = new EmployeeViewModel();
 9 
10       public EmployeeViewModel EmployeeViewModel
11       {
12           get => this.employeeViewModel;
13           set => this.SetProperty(ref employeeViewModel, value);
14       }
15 
16       public RegisterViewModel(IEventAggregator eventAggregator)
17       {
18           RegisterCommand = new DelegateCommand(Register);
19 
20           this.eventAggregator = eventAggregator;
21       }
22 
23       private void Register()
24       {
25           //点击登记时,发送消息到ViewList模块
26           this.eventAggregator.GetEvent<SelectEmployeeEvent>().Publish(this.EmployeeViewModel);
27       }
28   }

5、注册模块里的视图

此时我们再回到RegisterModule类,在RegisterTypes中注册View

 1  public class RegisterModule : Prism.Modularity.IModule
 2  {
 3      public void OnInitialized(IContainerProvider containerProvider)
 4      {
 5          
 6      }
 7 
 8      public void RegisterTypes(IContainerRegistry containerRegistry)
 9      {
10          //注册View的时候同步绑定ViewModel            
11          containerRegistry.RegisterForNavigation<RegisterView, RegisterViewModel>();
12 
13          //也可以只注册View
14          //然后通过ViewModelLocator.AutoWireViewModel附加属性来自动绑定ViewModel
15          //containerRegistry.RegisterForNavigation<RegisterView>();
16      }
17  }

这样我们就拥有了一个完整的登记模块

然后我们按照这个逻辑,再添加ViewList模块

ViewListModule.cs

 1 public class ViewListModule : IModule
 2 {
 3     public void OnInitialized(IContainerProvider containerProvider)
 4     {
 5         
 6     }
 7 
 8     public void RegisterTypes(IContainerRegistry containerRegistry)
 9     {
10         //注册视图
11         containerRegistry.RegisterForNavigation<EmployeeListView, EmployeeListViewModel>();
12     }
13 }

Views\EmployeeListView.xaml

 1 <Grid>
 2     <ListBox ItemsSource="{Binding EmployeeList}">
 3         <ListBox.ItemTemplate>
 4             <DataTemplate>
 5                 <Grid>
 6                     <Grid.RowDefinitions>
 7                         <RowDefinition/>
 8                         <RowDefinition/>
 9                     </Grid.RowDefinitions>
10 
11                     <TextBlock Text="{Binding Name}" HorizontalAlignment="Left" Margin="10,0,0,0" FontWeight="Bold" FontSize="13" Foreground="Blue"></TextBlock>
12                     <DockPanel Grid.Row="1" Margin="0,5,0,0">
13                         <TextBlock Text="Id:" Margin="10,0,5,0"></TextBlock>
14                         <TextBlock Text="{Binding Id}" Margin="5,0,10,0"></TextBlock>
15                         <TextBlock Text="Phone:" Margin="10,0,5,0"></TextBlock>
16                         <TextBlock Text="{Binding Phone}" FontStyle="Italic"></TextBlock>
17                     </DockPanel>
18                 </Grid>
19             </DataTemplate>
20         </ListBox.ItemTemplate>
21     </ListBox>
22 </Grid>

ViewModels\EmployeeListViewModel.cs

 1 public class EmployeeListViewModel : BindableBase
 2 {
 3     //列表
 4     private ObservableCollection<IEmployeeViewModel> employeeList = new ObservableCollection<IEmployeeViewModel>();
 5 
 6     public ObservableCollection<IEmployeeViewModel> EmployeeList
 7     {
 8         get => this.employeeList;
 9         set => this.SetProperty(ref employeeList, value);
10     }
11 
12     public EmployeeListViewModel(IEventAggregator eventAggregator)
13     {
14         //创建登记界面发送数据订阅
15         eventAggregator.GetEvent<SelectEmployeeEvent>().Subscribe(OnAddEmployee);
16     }
17 
18      //接收从登记界面发送过来的数据
19     private void OnAddEmployee(IEmployeeViewModel model)
20     {
21         this.EmployeeList.Add(model);
22     }
23 }

Prism模块加载流程

Prism模块加载流程如下图所示

exported_image

这里我们了解一下IModuleCatalog接口IModuleManager接口

IModuleCatalog接口

IModuleCatalog 是模块清单,负责 “记录” 应用中有哪些模块、加载规则和依赖关系,是静态的元数据存储;

 1  /// <summary>
 2  /// 这是ModuleManager的预期目录定义。ModuleCatalog包含应用程序可使用的模块信息。
 3  /// 每个模块都在ModuleInfo类中进行了描述,该类记录了模块的名称、类型和位置。
 4  /// </summary>
 5  public interface IModuleCatalog
 6  {
 7      /// <summary>
 8      /// 获取IModuleCatalog中的所有IModuleInfo类型
 9      /// </summary>
10      IEnumerable<IModuleInfo> Modules { get; }
11 
12      IEnumerable<IModuleInfo> GetDependentModules(IModuleInfo moduleInfo);
13 
14      IEnumerable<IModuleInfo> CompleteListWithDependencies(IEnumerable<IModuleInfo> modules);
15 
16      /// <summary>
17      /// 初始化目录,这可能会加载并验证模块。
18      /// </summary>
19      void Initialize();
20 
21      /// <summary>
22      /// 将IModuleInfo添加到IModuleCatalog中
23      /// </summary>
24      IModuleCatalog AddModule(IModuleInfo moduleInfo);
25  }

它会在Bootstrapper初始化时,进行初始化。过程如下所示:

 1 public abstract class PrismApplicationBase : Application
 2 {
 3     protected override void OnStartup(StartupEventArgs e)
 4     {
 5         InitializeInternal();
 6     }
 7 
 8     void InitializeInternal()
 9     {
10         Initialize();
11     }
12 
13     protected virtual void Initialize()
14     {
15         _moduleCatalog = CreateModuleCatalog();
16     }
17 
18     protected virtual IModuleCatalog CreateModuleCatalog()
19     {
20         return new ModuleCatalog();
21     }
22 }

IModuleManager

IModuleManager 是模块加载器,负责 “执行” 模块的加载和初始化,支持立即加载和按需加载,是动态的操作组件;

 1  /// <summary>
 2  /// Defines the interface for the service that will retrieve and initialize the application's modules.
 3  /// </summary>
 4  public interface IModuleManager
 5  {
 6      /// <summary>
 7      /// Gets all the <see cref="IModuleInfo"/> classes that are in the <see cref="IModuleCatalog"/>.
 8      /// </summary>
 9      IEnumerable<IModuleInfo> Modules { get; }
10 
11      /// <summary>
12      /// Initializes the modules marked as <see cref="InitializationMode.WhenAvailable"/> on the <see cref="IModuleCatalog"/>.
13      /// </summary>
14      void Run();
15 
16      /// <summary>
17      /// Loads and initializes the module on the <see cref="IModuleCatalog"/> with the name <paramref name="moduleName"/>.
18      /// </summary>
19      /// <param name="moduleName">Name of the module requested for initialization.</param>
20      void LoadModule(string moduleName);
21 
22      /// <summary>
23      /// Raised repeatedly to provide progress as modules are downloaded.
24      /// </summary>
25      event EventHandler<ModuleDownloadProgressChangedEventArgs> ModuleDownloadProgressChanged;
26 
27      /// <summary>
28      /// Raised when a module is loaded or fails to load.
29      /// </summary>
30      event EventHandler<LoadModuleCompletedEventArgs> LoadModuleCompleted;
31  }

IModuleManager也是在Bootstrapper初始化时进行初始化,调用流程如下所示

 1 public abstract class PrismApplicationBase : Application
 2 {
 3     protected override void OnStartup(StartupEventArgs e)
 4     {
 5         InitializeInternal();
 6     }
 7 
 8     void InitializeInternal()
 9     {
10         Initialize();
11     }
12 
13     protected virtual void Initialize()
14     {
15         RegisterRequiredTypes(_containerExtension);
16     }
17 
18     protected virtual void RegisterRequiredTypes(IContainerRegistry containerRegistry)
19     {
20        //注入IModuleManager单例
21         containerRegistry.RegisterSingleton<IModuleManager, ModuleManager>();
22     }
23 }

如何加载Prism模块

经过上述步骤,我们就创建好了两个Prism模块。接下来我们需要做的就是把它们加载到主窗口(Shell),然后一起工作。

Prism提供了5种加载模块的方法:

1、代码加载

2、目录扫描

3、手动加载

4、Xaml加载

5、AppConfig加载

这里的话只介绍前面三种方式,因为就我目前实际开发情况来看,后面两种方法用到的相对较少。

感兴趣的可以参考下面的代码自行学习:

https://github.com/PrismLibrary/Prism-Samples-Wpf/tree/master/07-Modules-AppConfig(AppConfig加载)

https://github.com/PrismLibrary/Prism-Samples-Wpf/tree/master/07-Modules-Xaml(Xaml加载)

代码加载

实现步骤如下:

1、在Shell工程上添加模块项目引用

image

引用我们需要使用的Prism模块项目

image

2、在Shell(MainWindow)的Bootstrapper中重写ConfigureModuleCatalog函数,配置要加载的模块

1  protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog)
2  {
3      //添加模块引用
4      moduleCatalog.AddModule<RegisterModule>();
5      moduleCatalog.AddModule<ViewListModule>();
6  }

3、在Shell(MainWindow)的Bootstrapper中加载View

1  protected override void OnInitialized()
2  {
3      base.OnInitialized();
4 
5      var regionManager = this.Container.Resolve<IRegionManager>();
6 
7      regionManager.RegisterViewWithRegion("EditArea", typeof(RegisterView));
8      regionManager.RegisterViewWithRegion("ListArea", typeof(EmployeeListView));
9  }

在前面我介绍介绍过,RegisterViewWithRegion函数可以绑定默认视图。

现在就等于将RegisterView绑定到EditArea区域,将EmployeeListView绑定到ListArea区域

RegisterViewEmployeeListView都分别来自于不同的模块。

程序运行效果如下:

image

demo

可以看到,这些功能虽然不是在一个模块里定义的,但最终可以被组装到一起,实现一个完整的功能 。

目录扫描

目录扫描主要是通过指定一个目录,然后Prism框架自动去扫描目录中符合要求的Prism模块。

实现步骤如下:

1、将模块输出到固定位置

例如我们将前面的两个模块输出到Modules目录下

Modules目录

image

项目输出路径

image

2、配置目录加载

 1  public partial class App : PrismApplication
 2  {
 3      protected override Window CreateShell()
 4      {
 5          return Container.Resolve<MainWindow>();
 6      }
 7 
 8      protected override void RegisterTypes(IContainerRegistry containerRegistry)
 9      {
10 
11      }
12 
13      protected override IModuleCatalog CreateModuleCatalog()
14      {
15          //指定目录
16          //可以使用相对路径也可以使用绝对路径
17          //推荐相对路径
18          return new DirectoryModuleCatalog() { ModulePath = @".\Modules" };
19      }
20  }

说明:在功能模块明确的情况下,推荐使用代码加载方式加载模块。有时候我们想动态扩展一些功能,可以使用目录加载。例如我有一款设备,在出厂时只有A型号,后期可能会增加B、C型号,或者更多。

手动加载

手动加载的整体流程和代码加载是一样的,都是需要引用项目工程。

在前面我们介绍了IModuleManager接口,它会在Bootstrapper初始化时,自动注入到容器中

手动加载模块主要用到IModuleManager接口。

实现步骤如下:

1、在Shell中增加一个按钮,用于手动加载模块

 1  <Grid>
 2      <Grid.RowDefinitions>
 3          <RowDefinition Height="35"/>
 4          <RowDefinition/>
 5      </Grid.RowDefinitions>
 6 
 7      <Grid Grid.Row="0">
 8          <Button Content="加载模块" HorizontalAlignment="Center" VerticalAlignment="Center" Width="88" Height="28" Command="{Binding ManualLoadModuleCommand}"/>
 9      </Grid>
10      
11      <Grid Grid.Row="1">
12          <Grid.ColumnDefinitions>
13              <ColumnDefinition/>
14              <ColumnDefinition/>
15          </Grid.ColumnDefinitions>
16 
17          <ContentControl prism:RegionManager.RegionName="EditArea"></ContentControl>
18          <ContentControl prism:RegionManager.RegionName="ListArea" Grid.Column="1"></ContentControl>
19      </Grid>
20  </Grid>

2、在Shell工程上添加模块项目引用

image

 引用我们需要使用的Prism模块项目

image

3、在Bootstrapper中重写ConfigureModuleCatalog函数,添加模块到IModuleCatalog中

 1   public partial class App : PrismApplication
 2   {
 3       protected override Window CreateShell()
 4       {
 5           return Container.Resolve<MainWindow>();
 6       }
 7 
 8       protected override void RegisterTypes(IContainerRegistry containerRegistry)
 9       {
10           
11       }
12 
13       /// <summary>
14       /// 配置模块
15       /// </summary>
16       /// <param name="moduleCatalog"></param>
17       protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog)
18       {
19           var moduleRegisterType = typeof(RegisterModule);
20           var moduleViewListType = typeof(ViewListModule);
21           moduleCatalog.AddModule(new ModuleInfo()
22           {
23               ModuleName = moduleRegisterType.Name,
24               ModuleType = moduleRegisterType.AssemblyQualifiedName,
25               InitializationMode = InitializationMode.OnDemand //需要时再加载
26           });
27           moduleCatalog.AddModule(new ModuleInfo()
28           {
29               ModuleName = moduleViewListType.Name,
30               ModuleType = moduleViewListType.AssemblyQualifiedName,
31               InitializationMode = InitializationMode.OnDemand //需要时再加载
32           });
33       }
34   }

4、在需要加载的地方,使用IModuleManager接口的LoadModule函数手动执行加载 

这里我们在ViewModel中进行加载

1  /// <summary>
2  /// 手动加载模块
3  /// </summary>
4  private void ManualLoadModule()
5  {
6      this.moduleManager.LoadModule("RegisterModule");
7      this.moduleManager.LoadModule("ViewListModule");
8  }

运行效果

demo

示例代码

https://github.com/zhaotianff/WPF-MVVM-Beginner/tree/main/15_Prism_Module.sln