Prismのソースコードをちゃんと読む（01-BoostrapperShell）

今まで何となくで触っていたPrismでしたが、一度しっかりソースコードを読み込んで見ようと思ったので記録として残します。
読み返した時にチートシート的な使い方ができるよう、ソースにコメントを入れていくスタイルでいきます。

# 01-BoostrapperShell
ここのサンプルコードをベースにソースを読んで使い方を理解する。
https://github.com/PrismLibrary/Prism-Samples-Wpf

## Prismの用語✨🌈
ここでは`Module`と`Region`、それから頻繁に出てくる`Resolve<T>`を理解しておきたいです。
https://elf-mission.net/programming/wpf/episode02/#Prism-2

### Region📟
画面領域の単位。一つのShell(=Window)に一つもしくは複数のRegionを配置できる。
https://elf-mission.net/programming/wpf/getting-started-2020/step05/#Module_View

### Module📁
機能単位で別れており、一つのRegionに一つもしくは複数のModuleを配置できる。
View, VMとIModuleを継承したクラスで１モジュールとなる。
https://ja.stackoverflow.com/questions/70833/prism-module%E5%88%86%E5%89%B2%E3%81%AE%E3%83%99%E3%82%B9%E3%83%88%E3%83%97%E3%83%A9%E3%82%AF%E3%83%86%E3%82%A3%E3%82%B9

PrismTemplateで生成した時点では何もしない処理は実装者がApp.OnStartUp()ないでoverrideして処理を追記する。

### Resolve\<T>🤲
これはPrismの概念というよりただの関数です。
PrismのDIコンテナに登録されたT型のインスタンスを取得するというもの。

## ソースコードを読む📑
今回は大した量がないのでサンプルの`App.xaml.cs`に直接コメントを書く形で記録しました。
ネストしている部分はその処理のなかで行われている処理を書いています。


```csharp
App.OnStartUp()
	// デフォルトではApp.xamlに`StartupUri=MainWindow.xaml`としてApp.xamlで最初の画面を開いている。
	// Prismで初回起動時に色々やりたいのでApp.xamlに記述する。
	base.OnStartUp() 
    /// Summary
    /// V-VMの紐付け、モジュールの設定、リージョンの設定、シェルの設定 を行う
    /// Summary
	Boostrapper.Run() 
        /// Summary
		/// View-ViewModelの紐付け設定
        /// V-VMの紐付け命名設定。命名ルールを変更したい場合overrideする https://prismlibrary.com/docs/viewmodel-locator.html
        /// Summary
        Boostrapper.ConfigureViewModelLocator();
			PrismInitializationExtensions.ConfigureViewModelLocator(); // V-VMの紐付け命名設定。命名ルールを変更したい場合overrideする https://prismlibrary.com/docs/viewmodel-locator.html
				ViewModelLocationProvider.SetDefaultViewModelFactory((object view, Type type) => ContainerLocator.Container.Resolve(type)); // デフォルトのV-VM紐付け設定
        /// Summary
		/// DIコンテナを使ってモジュールとリージョンの初期化
        /// Summary
        Boostrapper.Initialize();
            // コンテナを作成
			ContainerLocator.SetContainerExtension(CreateContainerExtension); // Lazy(Func<T>)にパラメータを与え遅延処理の準備。Lazyに登録しておくと値にアクセスするまでインスタンス化されずメモリ節約になる。https://www.kinakomotitti.net/entry/2018/08/17/125441
            _containerExtension = ContainerLocator.Current; // ContainerLoacater._currentにLazyに入れたコンテナーを入れてコンテナーを返す

            // モジュールカタログ作成
            // CreateModuleCatalogでの設定方法 https://feynman.hatenablog.com/entry/2019/07/03/080000#%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB%E3%81%AE%E7%B5%84%E3%81%BF%E8%BE%BC%E3%81%BF%E6%96%B9%E6%B3%95Appxamlcs
            // ConfigureModuleCatalogでの設定方法 https://elf-mission.net/programming/wpf/episode02/#Prism_Shell_Prism_63
            _moduleCatalog = CreateModuleCatalog(); // ModuleCatalogの初期化。
            RegisterRequiredTypes(_containerExtension); // 引数のModuleCatalog含め, Prismに必要なDIを行う。https://github.com/PrismLibrary/Prism/blob/master/src/Wpf/Prism.Wpf/PrismInitializationExtensions.cs
            RegisterTypes(_containerExtension); // Boostrapper.RegisterType()で実装者が登録した処理を実行=DIを行う
            _containerExtension.FinalizeExtension(); // 特に何もしていない。IContainerRegistry(Register系の処理を持つIF)とIContainerProvider(Resolve系の処理を持つIF)を継承しただけのIF。
            ConfigureModuleCatalog(_moduleCatalog); // Boostrapper.RegisterType()で実装者が登録した処理を実行=DIを行う。

            // リージョン作成
            // Custom Regionの設定 https://qiita.com/mngreen/items/f03d9a15eee1ed77f387
            RegionAdapterMappings regionAdapterMappings = _containerExtension.Resolve<RegionAdapterMappings>(); // RegionAdapterMappingsの登録(Resolve<T>)と初期設定
            ConfigureRegionAdapterMappings(regionAdapterMappings); // region adapter mappingという機能(UI Controlにリージョンを使い又、自動で登録する)のデフォルト設定をしている
            IRegionBehaviorFactory regionBehaviors = _containerExtension.Resolve<IRegionBehaviorFactory>(); // RegionBehaviorFactoryの登録(Resolve<T>)と初期設定
            ConfigureDefaultRegionBehaviors(regionBehaviors); // Regionにデフォルトのbehaviorを追加しIRegionBehaviorFactoryを設定している

            // 例外とならない型をExceptionExtensions指定する
            RegisterFrameworkExceptionTypes(); 

            // シェル(= MainWindow?)作成
            DependencyObject dependencyObject = CreateShell();
            if (dependencyObject != null)
            {
                MvvmHelpers.AutowireViewModel(dependencyObject); // ViewModelLocatorでのV-VMの紐付けがされてなければする
                RegionManager.SetRegionManager(dependencyObject, _containerExtension.Resolve<IRegionManager>()); // `RegionManager`プロパティをShellに登録
                RegionManager.UpdateRegions();
                InitializeShell(dependencyObject); // PrismBoostrapperBase.Shellに作ったShellを入れるだけ
            }

            InitializeModules(); // ModuleManagerを起動。containerProvider.Resolve<IModuleManager>().Run();している。

        /// Summary
        /// Shell(= MainWindow)を表示
        /// Summary
        Boostrapper.OnInitialized(); 

```

## まとめ🎈
* `Boostrapper > PrismBoostrapper > PrismBoostrapperBase`の順で継承されている。
* やっていることはV-VMの紐付け、モジュールの設定、リージョンの設定、シェルの設定。変更したい場合はApp.xaml.csでoverrideする。