7模块化Modules Prism官网案例学习
声明
原文出处如下:
这是一篇记录作者学习Prism的随笔,该随笔的内容是作者通过5个资源学习汇总而成,主要是为了方便自己以后拾遗温习所用,如果文中内容看不懂,推荐直接阅读相关原文。
Prism官网案例学习7-8模块化Modules
创建引入模块
-
prism模板创建模块-》并在内部初始化模块
public void OnInitialized(IContainerProvider containerProvider) { var regionManager = containerProvider.Resolve<IRegionManager>(); regionManager.RegisterViewWithRegion("ContentRegion", typeof(ViewA)); }
-
依赖项添加项目引用
-
App.xaml.cs中注册模块,设置为按需加载
protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog) { var moduleType = typeof(ModuleAModule); moduleCatalog.AddModule(new ModuleInfo() { ModuleName = moduleType.Name, ModuleType = moduleType.AssemblyQualifiedName, InitializationMode = InitializationMode.OnDemand, }); }
-
MainWondow.xaml.cs中加载模块
public partial class MainWindow : Window { IModuleManager _moduleManager; public MainWindow(IModuleManager moduleManager) { InitializeComponent(); _moduleManager = moduleManager; } private void Button_Click(object sender, RoutedEventArgs e) { _moduleManager.LoadModule("ModuleAModule"); } }
注册/发现模块->三种方式
代码注册
代码注册是没有所谓的发现模块部分,是直接开始注册,ViewModels中使用命令添加时,需要在MainWindowViewModel中_moduleManager = moduleManager;
-
注册模块:
//直接 protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog) { moduleCatalog.AddModule<ModuleA.ModuleAModule>(); } //按需 Copyprotected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog) { //直接 moduleCatalog.AddModule<PrismMetroSample.PatientModule.PatientModule>(); //将MedicineModule模块设置为按需加载 //反射获取模块信息 var MedicineModuleType = typeof(PrismMetroSample.MedicineModule.MedicineModule); //设置为按需加载 moduleCatalog.AddModule(new ModuleInfo() { //模块名 ModuleName= MedicineModuleType.Name, //模块类型 ModuleType=MedicineModuleType.AssemblyQualifiedName, //按需加载 初始化模式=按需 InitializationMode=InitializationMode.OnDemand }); } //-------------------------官方按需 protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog) { //反射获取模块信息 var moduleAType = typeof(ModuleAModule); //添加对应的模块信息 moduleCatalog.AddModule(new ModuleInfo() { ModuleName = moduleAType.Name, ModuleType = moduleAType.AssemblyQualifiedName, InitializationMode = InitializationMode.OnDemand }); }
目录文件扫描注册
-
注册模块:
-
设置是否按需加载:首先我们先在MedicineModule加上特性,OnDemand为true为"按需"加载,而PatientModule默认加载则可以不加
Copy [Module(ModuleName = "MedicineModule", OnDemand =true)]//设置是否按需加载 public class MedicineModule : IModule
-
生成事件DLL,拷贝到PrismMetroSample.Shell项目bin\Debug下的Modules文件夹下
我们将PrismMetroSample.MedicineModule项目和PrismMetroSample.PatientModule项目设置生成事件dll拷贝到PrismMetroSample.Shell项目bin\Debug下的Modules文件夹下
//生成事件命令行 Copyxcopy "$(TargetDir)$(TargetName)*$(TargetExt)" "$(SolutionDir)\PrismMetroSample.Shell\bin\Debug\netcoreapp3.1\Modules\" /Y /S
-
-
发现模块:
-
在App.xaml.cs重载实现该函数:
protected override IModuleCatalog CreateModuleCatalog(){ //获取该路径下的文件夹的模块目录 return new DirectoryModuleCatalog() { ModulePath = @".\Modules" }; }
-
初始化模块->使用配置文件App.config注册
-
注册模块:创建App.config文件,初始化模块->使用配置文件App.config注册
//注册模块 <module assemblyFile="ModuleA.dll" moduleType="ModuleA.ModuleAModule, ModuleA, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" moduleName="ModuleAModule" startupLoaded="True" />
-
发现模块:
protected override IModuleCatalog CreateModuleCatalog() { return new ConfigurationModuleCatalog();//加载配置文件模块目录 }
加载模块
prism应用程序加载模块有两种方式:
- 加载“可用时”的模块(默认方式)
- 根据情况加载“按需”模块
在代码注册时候,我将通过默认方式注册了PatientModule,然后注册MedicineModule将其设置为"按需"加载,“按需”加载有个好处就是,应用程序运行初始化后,MedicineModule模块是不加载到内存的,这样就提供了很大的灵活空间,默认我们可以加载一些"可用"的模块,然后我们可以根据自身要求去"按需"加载我们所需要的模块
这里可以讲解下按需加载MedicineModule的代码实现,首先我们已经在App.cs中将MedicineModule设置为"按需"加载,然后我们在主窗体通过一个按钮去加载MedicineModule,代码如下: MainWindowViewModle.cs:
Copy public class MainWindowViewModel : BindableBase
{
//模块管理器字段
IModuleManager _moduleManager;
public MainWindowViewModel(IModuleManager moduleManager)
{
_moduleManager = moduleManager;
}
private DelegateCommand _loadPatientModuleCommand;
public DelegateCommand LoadPatientModuleCommand =>
_loadPatientModuleCommand ?? (_loadPatientModuleCommand = new DelegateCommand(ExecuteLoadPatientModuleCommand));
void ExecuteLoadPatientModuleCommand()
{
//加载模块
_moduleManager.LoadModule("MedicineModule");
}
}
我们还可以去检测加载模块完成事件,我们MainWindowViewModle中加上这几句:
CopyIModuleManager _moduleManager;
public MainWindowViewModel(IModuleManager moduleManager)
{
_moduleManager = moduleManager;
_moduleManager.LoadModuleCompleted += _moduleManager_LoadModuleCompleted;
}
private void _moduleManager_LoadModuleCompleted(object sender, LoadModuleCompletedEventArgs e)
{
MessageBox.Show($"{e.ModuleInfo.ModuleName}模块被加载了");
}
初始化模块
示例1
新增一个类ModuleAModule.cs
实现IModule接口(每一个Module类都要实现这个接口,而每一个Module都要有这样一个类来对Module里的资源统一管理)
namespace ModuleA
{
public class ModuleAModule : IModule
{
public void OnInitialized(IContainerProvider containerProvider)
{
var regionManager = containerProvider.Resolve<IRegionManager>();
regionManager.RegisterViewWithRegion("ContentRegion", typeof(ViewA));
}
public void RegisterTypes(IContainerRegistry containerRegistry)
{
}
}
}
示例2
加载模块后,模块就会进行初始化,我们以MedicineModule为例子,先来看看代码:
Copy public class MedicineModule : IModule
{
public void OnInitialized(IContainerProvider containerProvider)
{
var regionManager = containerProvider.Resolve<IRegionManager>();
//MedicineMainContent 医学内容 regionManager.RegisterViewWithRegion(RegionNames.MedicineMainContentRegion, typeof(MedicineMainContent));
//SearchMedicine-Flyout 探诊
regionManager.RegisterViewWithRegion(RegionNames.FlyoutRegion, typeof(SearchMedicine));
//rightWindowCommandsRegion 右翼突击队regionManager.RegisterViewWithRegion(RegionNames.ShowSearchPatientRegion, typeof(ShowSearchPatient));
}
public void RegisterTypes(IContainerRegistry containerRegistry)
{
}
}
其中,IModule接口定义了两个函数OnInitialized和RegisterTypes,其中初始化顺序是RegisterTypes->OnInitialized,也就是RegisterTypes函数会先于OnInitialized函数,虽然这里我没在RegisterTypes写代码,但是这里通过是可以依赖注入到容器,给MedicineModule模块使用的,而OnInitialized我们通常会注册模块试图,或者订阅应用程序级别的事件和服务,这里我是将三个View分别分区域注册模块视图。