Prism コードサンプル学習：24-NavigationJournal

# Prism コードサンプル学習：24-NavigationJournal

## はじめに

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

## 24-NavigationJournal

本サンプルは、Personの一覧を表示するビューが表示されるサンプルになっており、その一覧の要素を選択するとそのPersonの詳細を表示するビューを表示します。
その表示されたビューの[Go Back]ボタンを押下すると一覧を表示するビューに戻り、[Go Forward]ボタンを押下するとさきほど表示していた詳細ビューを表示します。
つまり、戻る・進むボタンの実装にほぼ近いといえます。

とくに重要そうなのは、以下の処理の部分です。

```cs
...

namespace ModuleA.ViewModels
{
    public class PersonListViewModel : BindableBase, INavigationAware
    {
        IRegionNavigationJournal _journal;

        ...

        public DelegateCommand GoForwardCommand { get; set; }
        public PersonListViewModel(IRegionManager regionManager)
        {
            ...

            GoForwardCommand = new DelegateCommand(GoForward, CanGoForward);
        }

        ...

        public void OnNavigatedTo(NavigationContext navigationContext)
        {
            _journal = navigationContext.NavigationService.Journal;
            GoForwardCommand.RaiseCanExecuteChanged();
        }

        ...

        private void GoForward()
        {
            _journal.GoForward();
        }

        private bool CanGoForward()
        {
            return _journal != null && _journal.CanGoForward;
        }
    }

    public class PersonDetailViewModel : BindableBase, INavigationAware
    {
        private Person _selectedPerson;
        IRegionNavigationJournal _journal;
        public Person SelectedPerson
        {
            get { return _selectedPerson; }
            set { SetProperty(ref _selectedPerson, value); }
        }
        public DelegateCommand GoBackCommand { get; set; }
        public PersonDetailViewModel()
        {
            GoBackCommand = new DelegateCommand(GoBack);
        }

        public void OnNavigatedTo(NavigationContext navigationContext)
        {
            _journal = navigationContext.NavigationService.Journal;
            var person = navigationContext.Parameters["person"] as Person;
            if (person != null)
                SelectedPerson = person;
        }

        ...

        private void GoBack()
        {
            _journal.GoBack();
        }
    }
}
```

今回のサンプルでは、このIRegionNavigationJournalの責務がどのようなものか、また、このJournalというものを利用するとなぜ以前のビューに戻ることができるのかを読み進めようと思います。
経験的に、GoBackメソッドもGoForwardメソッドも似た内容だと思われるため、GoBackメソッドを取り上げて中身を見ていきます。
[IRegionNavigationJournal](https://github.com/PrismLibrary/Prism/blob/2bd2186faa404a2f48b79258cb9f892a5a1cf14d/src/Wpf/Prism.Wpf/Regions/IRegionNavigationJournal.cs#L19)を実現しているクラスを探すと、[RegionNavigationJournal](https://github.com/PrismLibrary/Prism/blob/master/src/Wpf/Prism.Wpf/Regions/RegionNavigationJournal.cs)クラスが見つかりました。
[GoBack](https://github.com/PrismLibrary/Prism/blob/master/src/Wpf/Prism.Wpf/Regions/RegionNavigationJournal.cs#L62)メソッドをみてみるとIRegionNavigationJournalEntryをStackで持っており、そのEntryを利用することで以前のビューに戻る処理を実現しています。
では、そのStackに積まれているインスタンスをどのタイミングで、どのような情報を持たせているのかを確認します。
同クラスに[RecordNavigation](https://github.com/PrismLibrary/Prism/blob/master/src/Wpf/Prism.Wpf/Regions/RegionNavigationJournal.cs#L116)メソッドがあるため、その利用箇所を探すと[RegionNavigationService.ExecuteNavigation](https://github.com/PrismLibrary/Prism/blob/2bd2186faa404a2f48b79258cb9f892a5a1cf14d/src/Wpf/Prism.Wpf/Regions/RegionNavigationService.cs#L221)メソッド内で利用されていることがわかります。
このメソッドを追っていくと[RequestNavigate](https://github.com/PrismLibrary/Prism/blob/2bd2186faa404a2f48b79258cb9f892a5a1cf14d/src/Wpf/Prism.Wpf/Regions/RegionNavigationService.cs#L101)メソッドにまで到達します。上コード内では省略しましたが、実際にビュー遷移させるときにはこのメソッドを使っているため、利用者は意識せずにビューの遷移情報が蓄積される仕組みになっています。

## おわりに

今回はRegionNavigationJournalクラスを読み進め、どのようにビューを戻す処理を実現しているのか読み進めました。
なるべく利用者には内側の仕組みを見せずに作るか、という点で勉強になりました。
次回、[29-InvokeCommandAction](https://github.com/PrismLibrary/Prism-Samples-Wpf/tree/master/29-InvokeCommandAction)について見ていこうと思います。