本文將介紹如何在.NET Core3環(huán)境下使用MVVM框架Prism的應(yīng)用程序的模塊化

          前言


          ?我們都知道,為了構(gòu)成一個低耦合,高內(nèi)聚的應(yīng)用程序,我們會分層,拿一個WPF程序來說,我們通過MVVM模式去將一個應(yīng)用程序的分成View-ViewModel-Model,大大消除之前業(yè)務(wù)邏輯和界面元素之間存在的高耦合,使我們后臺開發(fā)人員可以將重點更放在業(yè)務(wù)邏輯層面上,屬于UI界面的則可以交給更專業(yè)的UI人員


          ?但是一個應(yīng)用程序是由不同的業(yè)務(wù)模塊來組合而成,我們理想狀態(tài)下,每個業(yè)務(wù)模塊擁有著能夠獨立的功能,并且和其他業(yè)務(wù)模塊之間的是低耦合關(guān)系的,且每個業(yè)務(wù)模塊可以單獨用來開發(fā),測試和部署,這樣組成的應(yīng)用程序是非常容易擴展,測試和維護的,而Prism提供將應(yīng)用程序模塊化的功能

          我們先來看下一個小Demo

          再來看看解決方案的項目:



          我將該小demo,分為四個項目,其中Shell為主窗體項目,然后MedicineModule和PatientModule為我們分割開的業(yè)務(wù)模塊,最后Infrastructure則為我們的公共共享項目,我們將一步步講解該demo如何進行模塊化的.

          首先,我們引用官方的一個圖,大致講解了創(chuàng)建加載模塊的流程:


          * 注冊/發(fā)現(xiàn)模塊
          * 加載模塊
          * 初始化模塊
          我們就根據(jù)這個流程來看看demo是如何進行模塊化的?

          一.注冊/發(fā)現(xiàn)模塊

          1.注冊模塊

          prism注冊模塊有三種方式:

          * 代碼注冊
          * 目錄文件掃描注冊
          * 配置文件App.config注冊

          我們先用代碼注冊的方式,首先我們要先定義模塊,我們分別在PrismMetroSample.MedicineModule和PrismMetroSample.PatientModule兩個項目中創(chuàng)建MedicineModule類和PatientModule類,代碼如下:

          MedicineModule.cs:
          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) { } }
          PatientModule.cs:
          public class PatientModule : IModule { public void
          OnInitialized(IContainerProvider containerProvider) { var regionManager =
          containerProvider.Resolve<IRegionManager>(); //PatientList
          regionManager.RegisterViewWithRegion(RegionNames.PatientListRegion,
          typeof(PatientList)); //PatientDetail-Flyout
          regionManager.RegisterViewWithRegion(RegionNames.FlyoutRegion,
          typeof(PatientDetail)); } public void RegisterTypes(IContainerRegistry
          containerRegistry) { } }
          1.代碼注冊


          然后我們在PrismMetroSample.Shell主窗體的項目分別引用PrismMetroSample.MedicineModule和PrismMetroSample.PatientModule程序集,之后在App.xaml.cs中代碼注冊:
          protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog) {
          moduleCatalog.AddModule<PrismMetroSample.PatientModule.PatientModule>();
          //將MedicineModule模塊設(shè)置為按需加載 var MedicineModuleType =
          typeof(PrismMetroSample.MedicineModule.MedicineModule);
          moduleCatalog.AddModule(new ModuleInfo() { ModuleName= MedicineModuleType.Name,
          ModuleType=MedicineModuleType.AssemblyQualifiedName,
          InitializationMode=InitializationMode.OnDemand }); }
          注:代碼注冊是沒有所謂的發(fā)現(xiàn)模塊部分,是直接注冊部分

          2.目錄文件掃描注冊

          2.1注冊模塊

          首先我們先在MedicineModule加上特性,OnDemand為true為"按需"加載,而PatientModule默認(rèn)加載則可以不加
          [Module(ModuleName = "MedicineModule", OnDemand =true)] public class
          MedicineModule : IModule

          然后我們將PrismMetroSample.MedicineModule項目和PrismMetroSample.PatientModule項目設(shè)置生成事件dll拷貝到PrismMetroSample.Shell項目bin\Debug下的Modules文件夾下

          生成事件命令行如下:
          xcopy "$(TargetDir)$(TargetName)*$(TargetExt)"
          "$(SolutionDir)\PrismMetroSample.Shell\bin\Debug\netcoreapp3.1\Modules\" /Y /S
          2.2發(fā)現(xiàn)模塊

          然后我們在App.xaml.cs重載實現(xiàn)該函數(shù):
          protected override IModuleCatalog CreateModuleCatalog() { //獲取該路徑下的文件夾的模塊目錄
          return new DirectoryModuleCatalog() { ModulePath = @".\Modules" }; }
          3.使用配置文件App.config注冊

          3.1注冊模塊

          我們在主窗體項目PrismMetroSample.Shell添加一個App.config文件:

          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>
          其中startupLoaded為true則設(shè)置自動加載,為"可用時"模塊,為false則不加載,設(shè)置為“按需”模塊

          3.2發(fā)現(xiàn)模塊

          修改App.xaml.cs的CreateModuleCatalog函數(shù):
          App.xaml.cs:
          protected override IModuleCatalog CreateModuleCatalog() { return new
          ConfigurationModuleCatalog();//加載配置文件模塊目錄 }
          二.加載模塊

          prism應(yīng)用程序加載模塊有兩種方式:

          * 加載“可用時”的模塊(默認(rèn)方式)
          * 根據(jù)情況加載“按需”模塊

          ?在代碼注冊時候,我將通過默認(rèn)方式注冊了PatientModule,然后注冊MedicineModule將其設(shè)置為"按需"加載,“按需”加載有個好處就是,應(yīng)用程序運行初始化后,MedicineModule模塊是不加載到內(nèi)存的,這樣就提供了很大的靈活空間,默認(rèn)我們可以加載一些"可用"的模塊,然后我們可以根據(jù)自身要求去"按需"加載我們所需要的模塊


          ?這里可以講解下按需加載MedicineModule的代碼實現(xiàn),首先我們已經(jīng)在App.cs中將MedicineModule設(shè)置為"按需"加載,然后我們在主窗體通過一個按鈕去加載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>(); //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接口定義了兩個函數(shù)OnInitialized和RegisterTypes,其中初始化順序是RegisterTypes->OnInitialized,也就是RegisterTypes函數(shù)會先于OnInitialized函數(shù),雖然這里我沒在RegisterTypes寫代碼,但是這里通過是可以依賴注入到容器,給MedicineModule模塊使用的,而OnInitialized我們通常會注冊模塊試圖,或者訂閱應(yīng)用程序級別的事件和服務(wù),這里我是將三個View分別分區(qū)域注冊模塊視圖


          ?最后,其實一開始我們看到Demo演示,點擊病人列表,出來的病人詳細頁是沒有數(shù)據(jù)的,這涉及到窗體之間的通訊,病人列表和病人詳細頁屬于同一模塊,這很好辦,如何我要將搜索到的藥物加到當(dāng)前病人詳細頁的藥物列表里面,這就涉及到不同模塊窗體之間的通訊,處理不好是會造成模塊之間的強耦合,下篇我們會講到如何使用事件聚合器來實現(xiàn)同一模塊不同窗體的通訊和不同模塊不同窗體的通訊,而完整的Demo也會在下一篇放出。

          友情鏈接
          ioDraw流程圖
          API參考文檔
          OK工具箱
          云服務(wù)器優(yōu)惠
          阿里云優(yōu)惠券
          騰訊云優(yōu)惠券
          京東云優(yōu)惠券
          站點信息
          問題反饋
          郵箱:[email protected]
          QQ群:637538335
          關(guān)注微信

                一级黄色视频片 | 狼人综合网| 日日干天天干视频 | 伊人成人在线 | 久久久久无码人妻一区二区三区 |