3. Prism系列之模块化

Prism系列之模块化


一、前言

为了构成一个低耦合,高内聚的应用程序,我们会把程序分层,拿一个WPF程序来说,我们通过MVVM模式去将一个应用程序的分成View-ViewModel-Model,大大消除之前业务逻辑和界面元素之间存在的高耦合,使我们后台开发人员可以将重点更放在业务逻辑层面上,属于UI界面的则可以交给更专业的UI人员。

但是一个应用程序是由不同的业务模块来组合而成,我们理想状态下,每个业务模块拥有着能够独立的功能,并且和其他业务模块之间的是低耦合关系的,且每个业务模块可以单独用来开发,测试和部署,这样组成的应用程序是非常容易扩展,测试和维护的,而Prism提供将应用程序模块化的功能。

首先,我们引用官方的一个图,大致讲解了创建加载模块的流程:

在这里插入图片描述

加载模块的流程:

  1. 注册模块
  2. 发现模块
  3. 加载模块
  4. 初始化模块

二、注册模块

prism注册模块有三种方式:

  • 代码注册
  • 目录文件扫描注册
  • 配置文件App.config注册

先用代码注册的方式,首先我们要先定义模块,我们分别在PrismMetroSample.MedicineModulePrismMetroSample.PatientModule两个项目中创建MedicineModule类和PatientModule类,代码如下:

MedicineModule.cs:

using Prism.Ioc;
using Prism.Modularity;
using Prism.Regions;
using PrismMetroSample.Infrastructure.Constants;
using PrismMetroSample.MedicineModule.Views;namespace PrismMetroSample.MedicineModule
{[Module(ModuleName = "MedicineModule", OnDemand =true)]public class MedicineModule : IModule{public void OnInitialized(IContainerProvider containerProvider){var regionManager = containerProvider.Resolve<IRegionManager>();//MedicineMainContentregionManager.RegisterViewWithRegion(RegionNames.MedicineMainContentRegion, typeof(MedicineMainContent));//SearchMedicine-FlyoutregionManager.RegisterViewWithRegion(RegionNames.FlyoutRegion, typeof(SearchMedicine));//rightWindowCommandsRegionregionManager.RegisterViewWithRegion(RegionNames.ShowSearchPatientRegion, typeof(ShowSearchPatient));}public void RegisterTypes(IContainerRegistry containerRegistry){}}
}

PatientModule.cs:

using Prism.Ioc;
using Prism.Modularity;
using Prism.Regions;
using PrismMetroSample.Infrastructure.Constants;
using PrismMetroSample.PatientModule.Views;namespace PrismMetroSample.PatientModule
{public class PatientModule : IModule{public void OnInitialized(IContainerProvider containerProvider){var regionManager = containerProvider.Resolve<IRegionManager>();//PatientList//regionManager.RegisterViewWithRegion(RegionNames.PatientListRegion, typeof(PatientList));//PatientDetail-FlyoutregionManager.RegisterViewWithRegion(RegionNames.FlyoutRegion, typeof(PatientDetail));}public void RegisterTypes(IContainerRegistry containerRegistry){}}
}

1. 代码注册

PrismMetroSample.Shell主窗体的项目分别引用PrismMetroSample.MedicineModulePrismMetroSample.PatientModule程序集,之后在App.xaml.cs中代码注册:

protected 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});      }

注:代码注册是没有所谓的发现模块部分,是直接注册部分

2. 目录文件扫描注册

MedicineModule加上特性,OnDemandtrue为"按需"加载,而PatientModule默认加载则可以不加。

 [Module(ModuleName = "MedicineModule", OnDemand =true)]public class MedicineModule : IModule

PrismMetroSample.MedicineModule项目和PrismMetroSample.PatientModule项目设置生成事件dll拷贝到PrismMetroSample.Shell项目bin\Debug下的Modules文件夹下。

然后我们在App.xaml.cs重载实现该函数:

protected override IModuleCatalog CreateModuleCatalog()
{//获取该路径下的文件夹的模块目录return new DirectoryModuleCatalog() { ModulePath = @".\Modules" };
}

3. 使用配置文件App.config注册

在主窗体项目PrismMetroSample.Shell添加一个App.config文件:

<?xml version="1.0" encoding="utf-8" ?>
<configuration><configSections><section name="modules" type="Prism.Modularity.ModulesConfigurationSection, Prism.Wpf"/></configSections><modules><!--注册PatientModule模块--><module assemblyFile="PrismMetroSample.PatientModule.dll" moduleType="PrismMetroSample.PatientModule.PatientModule, PrismMetroSample.PatientModule, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" moduleName="PatientModule" startupLoaded="True" /><!--注册MedicineModule模块--><module assemblyFile="PrismMetroSample.MedicineModule.dll" moduleType="PrismMetroSample.MedicineModule.MedicineModule, PrismMetroSample.MedicineModule, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" moduleName="MedicineModule" startupLoaded="false" /></modules>
</configuration>

其中startupLoadedtrue则设置自动加载,为"可用时"模块,为false则不加载,设置为“按需”模块。

修改App.xaml.cs的CreateModuleCatalog函数:
App.xaml.cs:

 protected override IModuleCatalog CreateModuleCatalog(){return new ConfigurationModuleCatalog();//加载配置文件模块目录}

三、加载模块

prism应用程序加载模块有两种方式:

  • 加载“可用时”的模块(默认方式)
  • 根据情况加载“按需”模块

在代码注册时候,我们将通过默认方式注册了PatientModule,然后注册MedicineModule将其设置为"按需"加载,“按需”加载有个好处就是,应用程序运行初始化后,MedicineModule模块是不加载到内存的,这样就提供了很大的灵活空间,默认我们可以加载一些"可用"的模块,然后我们可以根据自身要求去"按需"加载我们所需要的模块。

这里可以讲解下按需加载MedicineModule的代码实现,首先我们已经在App.cs中将MedicineModule设置为"按需"加载,然后我们在主窗体通过一个按钮去加载MedicineModule,代码如下:

MainWindowViewModle.cs:

 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中加上这几句:

IModuleManager _moduleManager;
public MainWindowViewModel(IModuleManager moduleManager)
{_moduleManager = moduleManager;_moduleManager.LoadModuleCompleted += _moduleManager_LoadModuleCompleted;
}private void _moduleManager_LoadModuleCompleted(object sender, LoadModuleCompletedEventArgs e)
{MessageBox.Show($"{e.ModuleInfo.ModuleName}模块被加载了");
}

在模块加载完后,会跳出提示框。

四、初始化模块

加载模块后,模块就会进行初始化,我们以MedicineModule为例子,先来看看代码:

 public class MedicineModule : IModule{public void OnInitialized(IContainerProvider containerProvider){var regionManager = containerProvider.Resolve<IRegionManager>();//MedicineMainContentregionManager.RegisterViewWithRegion(RegionNames.MedicineMainContentRegion, typeof(MedicineMainContent));//SearchMedicine-FlyoutregionManager.RegisterViewWithRegion(RegionNames.FlyoutRegion, typeof(SearchMedicine));//rightWindowCommandsRegionregionManager.RegisterViewWithRegion(RegionNames.ShowSearchPatientRegion, typeof(ShowSearchPatient));}public void RegisterTypes(IContainerRegistry containerRegistry){}}

其中,IModule接口定义了两个函数OnInitializedRegisterTypes,其中初始化顺序是RegisterTypes->OnInitialized,也就是RegisterTypes函数会先于OnInitialized函数,虽然这里我没在RegisterTypes写代码,但是这里通过是可以依赖注入到容器,给MedicineModule模块使用的,而OnInitialized我们通常会注册模块试图,或者订阅应用程序级别的事件和服务,这里我是将三个View分别分区域注册模块视图。

最后,其实一开始我们看到Demo演示,点击病人列表,出来的病人详细页是没有数据的,这涉及到窗体之间的通讯,病人列表和病人详细页属于同一模块,这很好办,如何我要将搜索到的药物加到当前病人详细页的药物列表里面,这就涉及到不同模块窗体之间的通讯,处理不好是会造成模块之间的强耦合,下篇我们会讲到如何使用事件聚合器来实现同一模块不同窗体的通讯和不同模块不同窗体的通讯。

回到顶部


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/277608.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言刷题数组------数组交换

输入一个长度为 10的整数数组 X[10]&#xff0c;将里面的非正整数全部替换为 1&#xff0c;输出替换完成后的数组。 输入格式 输入包含 10个整数&#xff0c;每个整数占一行。输出格式 输出新数组中的所有元素&#xff0c;每个元素占一行。输出格式为 X[i] x&#xff0c;其中…

geolife笔记:比较不同轨迹相似度方法

1 问题描述 在geolife 笔记&#xff1a;将所有轨迹放入一个DataFrame-CSDN博客中&#xff0c;已经将所有的轨迹放入一个DataFrame中了&#xff0c;我们现在需要比较&#xff0c;在不同的轨迹距离度量方法下&#xff0c;轨迹相似度的效果。 这里采用论文笔记&#xff1a;Deep R…

C# WPF上位机开发(利用tcp/ip网络访问plc)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 c# wpf如果是用来开发非标上位机的&#xff0c;那么和plc的通信肯定是少不了的。而且&#xff0c;大部分plc都支持modbus协议&#xff0c;所以这个…

基于ssm企业人事管理系统的设计与实现论文

摘 要 进入信息时代以来&#xff0c;很多数据都需要配套软件协助处理&#xff0c;这样可以解决传统方式带来的管理困扰。比如耗时长&#xff0c;成本高&#xff0c;维护数据困难&#xff0c;数据易丢失等缺点。本次使用数据库工具MySQL和编程技术SSM开发的企业人事管理系统&am…

python:五种算法(CSO、WOA、GWO、DBO、PSO)求解23个测试函数(python代码)

一、五种算法简介 1、鸡群优化算法CSO 2、鲸鱼优化算法WOA 3、灰狼优化算法GWO 4、蜣螂优化算法DBO 5、粒子群优化算法PSO 二、5种算法求解23个函数 &#xff08;1&#xff09;23个函数简介 参考文献&#xff1a; [1] Yao X, Liu Y, Lin G M. Evolutionary programming…

Windows安装Tesseract OCR与Python中使用pytesseract进行文字识别

文章目录 前言一、下载并安装Tesseract OCR二、配置环境变量三、Python中安装使用pytesseract总结 前言 Tesseract OCR是一个开源OCR&#xff08;Optical Character Recognition&#xff09;引擎&#xff0c;用于从图像中提取文本。Pytesseract是Tesseract OCR的Python封装&am…

一款提高嵌入式代码质量的工具

我们通常认为&#xff0c;在中断中&#xff0c;不能执行耗时的操作&#xff0c;否则会影响系统的稳定性&#xff0c;尤其对于嵌入式编程。 ​ 对于带操作系统的程序而言&#xff0c;可以通过操作系统的调度&#xff0c;将中断处理分成两个部分&#xff0c;耗时的操作可以放到线…

DTC 故障严重程度

文章目录 简介DTC严重性 位定义DTC 类别定义参考 简介 DTCSeverityMask&#xff08;DTC严重性掩码&#xff09;/ DTCSeverity&#xff08;DTC严重性&#xff09;包含了DTC严重性和DTC类别信息。 DTCSeverityMask&#xff08;DTC严重性掩码&#xff09;&#xff0f;DTCSeverit…

国标级联/流媒体音视频平台EasyCVR设备录像下载异常该如何解决?

视频监控TSINGSEE青犀视频平台EasyCVR能在复杂的网络环境中&#xff0c;将分散的各类视频资源进行统一汇聚、整合、集中管理&#xff0c;在视频监控播放上&#xff0c;视频安防监控汇聚平台可支持1、4、9、16个画面窗口播放&#xff0c;可同时播放多路视频流&#xff0c;也能支…

项目篇 | 图书管理系统 | 图像加载与绘制

项目篇 | 图书管理系统 | 图像加载与绘制 基本介绍 首先解释清楚什么叫图像加载与绘制,意思就是说项目中需要用到一些图片资源(各种图标),我们要在图书管理系统中展示这些图片,就需要先导入图片到项目中,再加载图片资源(通过资源路径)、绘制图片(即展示)。 注:如果…

Shell三剑客:文本过滤工具——grep

一、简介&#xff1a;过滤&#xff0c;查找文档中的内容 二、分类 grepegrep——扩展支持正则\w所有字母与数字&#xff0c;称为字符[a-zA-Z0-9] l[a-zA-Z0-9]*ve l\w*ve\W所有字母与数字之外的字符&#xff0c;称为非字符 love[^a-zA-Z0-9] love\W\b词边界 \<love\>…

FindMy技术用于滑雪板

随着冬季运动的日益普及&#xff0c;滑雪板作为滑雪运动的重要器材&#xff0c;也变得越来越受欢迎。在各大雪场和户外运动场所&#xff0c;人们纷纷挥舞着滑雪板&#xff0c;畅享冬季运动的乐趣。 在滑雪过程中&#xff0c;由于雪场的复杂环境和运动的高速性&#xff0c;很容易…