はじめに
いつもお世話になっているPrismなんですけど、使い方を習熟するべく元のソースを見ていたら知らない機能があったため、勉強がてら投稿させていただきます。
機能確認用プロジェクト
Prism7Sample(自作)
Prism-Samples-Wpf(公式) 24-NavigationJournal
環境
Prism.DryIoc.7.1.0.172-pre
Prism.Wpf.7.1.0.172-pre
Prism.Core.7.1.0.172-pre
.NET Framework: 4.7.2
IRegionNavigationServiceについて
皆様はIRegionNavigationServiceの存在はご存知でしたでしょうか。INavigationAwareのOnNavigatedToやOnNavigatedFromの仮引数であるNavigationContextのメンバであるNavigationServiceから取得できます。
private IRegionNavigationService RegionNavigationService { get; set; }
public void OnNavigatedTo(NavigationContext navigationContext)
{
RegionNavigationService = navigationContext.NavigationService;
}
このIRegionNavigationServiceはINavigateAsyncを継承しているため、IRegionManagerをDIコンテナから注入しなくてもRequestNavigateすることができます。しかもIRegionManagerでRequestNavigateするときは毎回RegionNameを指定する必要がありましたがIRegionNavigationServiceのRequestNavigateでは記述する必要がありません。
RegionManager.RequestNavigate("ContentRegion", nameof(yyyView));
RegionNavigationService.RequestNavigate(nameof(yyyView));
同一Region内で画面遷移をするのならばIRegionNavigationService、別のRegionの画面を操作する必要がある場合はIRegionManagerと使い分けできます。
IRegionNavigationJournalについて
また、IRegionNavigationServiceはJournalというメンバも持っています。このJournalはIRegionNavigationJournalの型で名前の通り、Region内のナビゲーションの履歴を管理してくれています。IRegionNavigationServiceのRequestNavigateを使用して画面遷移しているとGoBackやGoForwardを使用して戻る進む機能を実現できます。例えば段階的に画面が遷移するようなシステムでひとつ前に戻るようなボタンを実装する際はRequestNavigateで個別のView名を記述するよりもGoBackで実装するほうが問題になりにくいのではないかと思います。
以下に戻る、進むボタンの実装例を記載します。
public class ContentViewModel : BindableBase, INavigationAware
{
private IRegionNavigationService RegionNavigationService { get; set; }
public DelegateCommand BackCommand { get; }
public DelegateCommand ForwardCommand { get; }
public ContentViewModel()
{
BackCommand = new DelegateCommand(() => RegionNavigationService.Journal.GoBack(), () => RegionNavigationService?.Journal?.CanGoBack ?? false);
ForwardCommand = new DelegateCommand(() => RegionNavigationService.Journal.GoForward(), () => RegionNavigationService?.Journal?.CanGoForward ?? false);
}
public void OnNavigatedTo(NavigationContext navigationContext)
{
RegionNavigationService = navigationContext.NavigationService;
BackCommand.RaiseCanExecuteChanged();
ForwardCommand.RaiseCanExecuteChanged();
}
public bool IsNavigationTarget(NavigationContext navigationContext) => true;
public void OnNavigatedFrom(NavigationContext navigationContext){}
}
IJournalAwareについて
ViewModelにIJournalAwareを継承しているとIRegionNavigationJournalでの履歴の保存可否を指定することができます。
例えばメニュー画面->認証画面->詳細画面と遷移するようなシステムにおいて、詳細画面からメニュー画面に戻りたい(認証画面にGoBackしたくない)等で必要になるかと思います。ViewModelにてIJournalAwareを継承していない場合は保存する(true)を返すようになっていました。
public class ContentViewModel : BindableBase, IJournalAware
{
public bool PersistInHistory() => true;
}
RecordNavigationについて
履歴の記録はIRegionNavigationJournalのRecordNavigationを実行することで自分で保存することもできます。しかしIRegionNavigationServiceの実装であるRegionNavigationServiceのRequestNavigateにてRecordNavigationしてくれているので自分で実行する機会はあんまりないかと思います。
またIRegionManagerの実装であるRegionManagerのRequestNavigateではRecordNavigationしていないので注意が必要です。
戻る進む機能を利用する際は、RegionNavigationServiceのRequestNavigateを使用するようにしましょう。
まとめ
- 同一Region内で遷移するならIRegionManagerよりもIRegionNavigationService
- 戻る進む機能(IRegionNavigationJournal)便利