Prism コードサンプル学習：17-BasicRegionNavigation

# Prism コードサンプル学習：17-BasicRegionNavigation

## はじめに

以下の記事の続きです。
<https://qiita.com/mngreen/items/c5ea46557522c8128593>

## 17-BasicRegionNavigation

本サンプルは、RegionManager.RequestNavigateメソッドを用いてコントロールを切り替える例です。
実際にRegionManager.RegionNavigateを利用している箇所は以下です。
Navigateメソッドで受け取った引数の文字列にしたがい、ContentRegionの持つコントロールを切り替えています。

```cs
using Prism.Commands;
using Prism.Mvvm;
using Prism.Regions;
namespace BasicRegionNavigation.ViewModels
{
    public class MainWindowViewModel : BindableBase
    {
        private readonly IRegionManager _regionManager;
        private string _title = "Prism Unity Application";
        public string Title
        {
            get { return _title; }
            set { SetProperty(ref _title, value); }
        }
        public DelegateCommand<string> NavigateCommand { get; private set; }
        public MainWindowViewModel(IRegionManager regionManager)
        {
            _regionManager = regionManager;
            NavigateCommand = new DelegateCommand<string>(Navigate);
        }
        private void Navigate(string navigatePath)
        {
            if (navigatePath != null)
                _regionManager.RequestNavigate("ContentRegion", navigatePath);
        }
    }
}
```

上記でコントロールを切り替えるためには、モジュール側で以下の通り事前に登録する必要があります。
登録時には名前を指定することもできますが、指定しない場合はその型通りの名前となる仕様のようです。

```cs
using ModuleA.Views;
using Prism.Ioc;
using Prism.Modularity;
namespace ModuleA
{
    public class ModuleAModule : IModule
    {
        public void OnInitialized(IContainerProvider containerProvider)
        {
        }
        public void RegisterTypes(IContainerRegistry containerRegistry)
        {
            containerRegistry.RegisterForNavigation<ViewA>();
            containerRegistry.RegisterForNavigation<ViewB>();
        }
    }
}
```

コードを見る限り、RegionManagerとIContainerRegistryがお互いに参照関係を持たないとビューを切り替えられないように見えますがどのようにして連携しているのでしょうか？
[RequestNavigate](https://github.com/PrismLibrary/Prism/blob/7f0b1680bbe754da790274f80851265f808d9bbf/src/Wpf/Prism.Wpf/Regions/RegionManager.cs#L410)メソッドが呼び出されると、巡り巡ってRegionクラスの[RequestNavigate](https://github.com/PrismLibrary/Prism/blob/7f0b1680bbe754da790274f80851265f808d9bbf/src/Wpf/Prism.Wpf/Regions/Region.cs#L368)メソッドが呼び出され、さらにRegionNavigationServiceクラスに委譲します。
NavigationServiceクラスを読み出し元を順に辿っていくと、[RequestCanNavigateFromOnCurrentlyActiveView](https://github.com/PrismLibrary/Prism/blob/7f0b1680bbe754da790274f80851265f808d9bbf/src/Wpf/Prism.Wpf/Regions/RegionNavigationService.cs#L134)メソッドにたどり着き、[140行目](https://github.com/PrismLibrary/Prism/blob/7f0b1680bbe754da790274f80851265f808d9bbf/src/Wpf/Prism.Wpf/Regions/RegionNavigationService.cs#L140)を満たさない場合のみ（つまり、currentViewIndex >= activeViews.Length。ただ、あまり意図がわかっていない。遷移させたいビューがアクティブでないときに限って遷移させるということ？）、[ExecuteNavigation](https://github.com/PrismLibrary/Prism/blob/7f0b1680bbe754da790274f80851265f808d9bbf/src/Wpf/Prism.Wpf/Regions/RegionNavigationService.cs#L221)メソッドを実行します。 この中で[CreateNewRegionItem](https://github.com/PrismLibrary/Prism/blob/7f0b1680bbe754da790274f80851265f808d9bbf/src/Wpf/Prism.Wpf/Regions/RegionNavigationContentLoader.cs#L111)メソッドが呼び出されることでコンテナーからViewインスタンスを生成し、ようやくRegionに対してViewが追加されます（<https://github.com/PrismLibrary/Prism/blob/7f0b1680bbe754da790274f80851265f808d9bbf/src/Wpf/Prism.Wpf/Regions/RegionNavigationContentLoader.cs#L51>）。

つまり、RegionManager－Region－RegionNavigationService－IContainerExtension（IContainerRegistry）という関連を持つことで、上記の振る舞いが実現できているようでした。

## おわりに

今回は、RegionManager.RequestNavigateメソッドを用いてコントロールを切り替える例についてコードを読みました。
ユーザーから見ると型の文字列を入力にわたすだけで簡単にコントロールが切り替えられているようにみるのですが、その裏には責務ごとに切り分けられたI/Fとクラスが存在しており、緻密に連携して見えました。
次回、[18-NavigationCallback](https://github.com/PrismLibrary/Prism-Samples-Wpf/tree/master/18-NavigationCallback)について見ていこうと思います。