この記事は転載から
著者:Ryzen Adorer
前の記事:. NET Core 3 WPF MVVMフレームワークPrismシリーズのモジュール性
原文へのリンク:https//www.cnblogs.com/ryzen/p/12185054.html
この記事では、. NET Core3環境でMVVMフレームワークPrismを使用したアプリケーションのモジュール化方法を説明します。
1. 前のページ
私たちは皆、低結合、高凝集アプリケーションを構成するために、WPFプログラムを取るために、MVVMパターンを介してアプリケーションをView-ViewModel-Modelに分割し、以前のビジネスロジックとインターフェイス要素間の高結合を大幅に排除するので、バックエンド開発者はビジネスロジックレベルにもっと焦点を当てることができ、UIインターフェイスに属するものは、よりプロフェッショナルなUI担当者に渡すことができます。
しかし、アプリケーションは異なるビジネスモジュールで構成されています。理想的には、各ビジネスモジュールが独立した機能を持ち、他のビジネスモジュールとの結合が低く、各ビジネスモジュールを個別に開発、テスト、デプロイすることができ、構成されたアプリケーションは非常に簡単に拡張、テスト、保守できます。
次のデモを見てみましょう。

ソリューションプロジェクトを見てみましょう。

私はこの小さなデモを4つのプロジェクトに分けました。シェルはメインフォームプロジェクトで、次にMedicineModuleとPatientModuleは私たちが分割したビジネスモジュールで、最後にInfrastructureは私たちのパブリック共有プロジェクトです。
まず、ロードモジュールの作成プロセスを概説した公式図を参照してください。

- 登録/発見モジュール
- モジュールの読み込み
- モジュールの初期化
デモがどのようにモジュール化されるかを見てみましょう。
2. 登録/発見モジュール
2.1.モジュールの登録
Prismモジュールには3つの方法があります。
- コードの登録
- カタログ·ファイルのスキャン登録
- ファイルApp.config
私たちはコードで登録する方式で、まずモジュールを定義する必要があります。PrismMetroSample.MedicineModuleとPrismMetroSample.PatientModuleの2つのプロジェクトで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)
{
}
}
2.1.1.コードの登録
次に、PrismMetroSample.ShellのメインフォームのプロジェクトでPrismMetroSample.MedicineModuleとPrismMetroSample.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.1.2.カタログ·ファイルのスキャン登録
2.1.2.1.モジュールの登録
まず、MedicineModuleに機能を追加します。OnDemandがtrueの場合はオンデマンドでロードされ、PatientModuleはデフォルトでロードされません。
[Module(ModuleName = "MedicineModule", OnDemand =true)]
public class MedicineModule : IModule
次に、PrismMetroSample.MedicineModuleプロジェクトとPrismMetroSample.PatientModuleプロジェクト設定ビルドイベントdllをPrismMetroSample.Shellプロジェクトbin\Debugの下のModulesフォルダにコピーします。
イベントの生成コマンド·ラインは次のとおりです。
xcopy "$(TargetDir)$(TargetName)*$(TargetExt)" "$(SolutionDir)\PrismMetroSample.Shell\bin\Debug\netcoreapp3.1\Modules\" /Y /S
2.1.2.2.ディスカバリモジュール
次に、App.xaml.csオーバーロードで関数を実装します。
protected override IModuleCatalog CreateModuleCatalog()
{
//获取该路径下的文件夹的模块目录
return new DirectoryModuleCatalog() { ModulePath = @".\Modules" };
}
2.1.3.設定ファイルApp.configを使用して#を登録する
2.1.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の場合は自動ロード、“使用可能なとき”モジュール、falseの場合はロードしない場合は“オンデマンド”モジュールに設定
2.1.3.2. Discoveryモジュール
App.xaml.csのCreateModuleCatalog関数を変更する
App.xaml.cs:
protected override IModuleCatalog CreateModuleCatalog()
{
return new ConfigurationModuleCatalog();//加载配置文件模块目录
}
3. モジュールの読み込み
prismアプリケーションは2つの方法でモジュールをロードします。
- “使用可能なとき”モジュールのロードデフォルト
- 状況に応じてオンデマンド·モジュールをロード
コードを登録するとき、私はデフォルトで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}模块被加载了");
}
効果は以下の通りです

4. モジュールの初期化
モジュールがロードされるとモジュールが初期化されます。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インターフェイスは2つの関数OnInitializedとRegisterTypesを定義しています。ここで、初期化順序はRegisterTypes->OnInitializedです。つまり、RegisterTypes関数はOnInitialized関数の前にあります。ここではRegisterTypesでコードを書いていませんが、ここではコンテナへの依存注入を介してMedicineModuleモジュールが使用し、OnInitializedは通常、モジュールの試みを登録したり、アプリケーションレベルのイベントやサービスを購読したりすることができます。ここでは、3つのビューをそれぞれゾーン登録モジュールビューに分割します。
最后に、実际に私达は最初にデモを见て、患者のリストをクリックして、出てきた患者の详细ページはデータがなく、これはフォーム間の通信に関与して、患者のリストと患者の详细ページは同じモジュールに属して、これは非常にうまくいく、どのように検索された薬を現在の患者の详细ページの薬のリストに追加して、これは異なるモジュールのフォーム間の通信に関与して、処理が悪いのはモジュール間の強い結合を引き起こして、次の記事では、イベントアグリゲーターを使用して、同じモジュールの異なるフォーム間の通信や、異なるモジュールの異なるフォーム間の通信を実現する方法について説明します。完全なデモも次の記事で公開されます。