WPF Prism episode: 7 ~ 画面遷移のパラメータたちが INavigationAware から来るそうですよ? ~

前回記事「いつだって Prism の画面遷移は RequestNavigation だった。【episode: 6.5 WPF Prism】」

 

前回は TreeView の SelectedItemChanged イベントで MainWindow 左側の View を動的に切り替える方法と、View の切り替え時にパラメータを渡す方法を紹介しました。
今回は Prism の RequestNavigate メソッドに設定したパラメータを View 側(VM)で受け取る方法を紹介します。

※ Google 等の検索エンジンから来た方へ
このエントリは 2019/6/7 をもってリニューアルしたため、元々 episode: 7 のタイトルで公開していた内容は extra: 2episode: 8 に分割しました。お手数ですがそれぞれの記事へ移動してください。

尚、この記事は Visual Studio 2017 Community Edition で .NET Framework 4.7.2 以上 と C# + Prism 7.1 + ReactiveProperty を使用して 、WPF アプリケーションを MVVM パターンで作成するのが目的で、C# での基本的なコーディング知識を持っている人が対象です。

Prism から動的に表示する View へパラメータを受け渡す

Prism の IRegionManager.RequestNavigate メソッドは fig. 1 の矢印で示した方向へパラメータを渡すことができます。
(View1 → View2 → View3 の順に切り替わる場合の例)

fig.1 パラメータを渡す方向

 

IRegionManager.RequestNavigate 呼び出し時にパラメータを設定する方法は episode: 6.5 で紹介しましたが、設定したパラメータを View 側(VM)で受け取るには INavigationAware を継承する必要があります

Prism の INavigationAware を使用したパラメータの受け取り

episode: 6.5 でも紹介しましたが、RequestNavigate にパラメータをセットするには src. 1 のように記述します。

src. 1 のように RequestNavigate にセットされたパラメータを受け取るために必要な INavigationAware には以下の 3 つのメンバが含まれています。

  • void OnNavigatedTo(NavigationContext)
  • void OnNavigatedFrom(NavigationContext)
  • bool IsNavigationTarget(NavigationContext)

RequestNavigate にセットしたパラメータは上記 3 つ全てで受け取る事が出来ますが、View が表示されたタイミングでパラメータを受け取りたい場合は OnNavigatedTo イベント(メソッド)を使用します。

INavigationAware.OnNavigatedTo イベントでパラメータを受け取る

OnNavigatedTo はメソッドとして定義されていますが、イベントと同じようなものなのでこの連載では OnNavigatedTo イベントと表記します。

OnNavigatedTo イベントは INavigationAware を継承した View(VM)へ遷移したタイミングで呼出され、RequestNavigate でセットされたパラメータを受け取るには src. 2 のように実装します。

38 行目のように RequestNavigate にパラメータをセットした時と同じキーワードを指定してパラメータを取得します。
OnNavigatedTo 以外のメンバは後で紹介するので、とりあえず例外が飛ばないようにしておきます。

取得したパラメータの値をバインドプロパティへセット(40 ~ 42 行目)すると fig. 2 のように編集 View が表示されたタイミングでデータが表示されるようになります。

fig.2 パラメータの値を表示した View

View の PersonalEditor.xaml は特に説明が必要なところも無さそうなので GitHub リポジトリ で見てください。

尚、今回紹介するサンプルコードは ReactiveProperty ではなく全て Prism の BindableBaseを使用して View とバインドします。
ReactiveProperty を編集データにバインドする例は次回 episode: 8 で紹介する予定です。



INavigationAware.IsNavigationTarget で表示する View を判別する

前回の extra: 3 で TreeViewItem へコンテキストメニューを追加して『新しい測定データ』や『新しい試験日』を追加できるようにしました。
先に extra でコンテキストメニューの追加を紹介したのはこのメソッドを紹介するためです。

又、episode: 6.5 で紹介した通り RequestNavigate で表示する View は src. 3 のように予め DI コンテナ(ここでは Unity)へ登録する必要があります。

DI コンテナには View の型(Type)を登録しているだけなので、実際に表示する View のインスタンスは DI コンテナで生成されます

前章で紹介した個人識別情報データのように必要な View のインスタンスが 1 つだけであれば良いのですが、『新しい測定データ』や『新しい試験日』のように View のインスタンスが複数必要な場合は View を新たに生成する必要があるか、既存の View を再表示するかを判別する必要があります

そのような場合に呼び出されるのが IsNavigationTarget で、false を返した場合は View の新規インスタンスが生成され、true を返した View が表示されます
IsNavigationTarget は RequestNavigate で指定した View のインスタンスが DI コンテナ内に 1 つ以上存在する場合は OnNavigatedTo より前に呼び出され、View のインスタンスが存在しない場合は呼び出されません。

src. 2 のように IsNavigationTarget で常に true を返すと fig. 3 のような動作になります。

fig.3 IsNavigationTarget で常に true を返した場合の動作

fig. 3 のように新しい項目を追加して画面を切り替えても常に同じ画面が表示されます。

IsNavigationTarget も OnNavigatedTo と同じく RequestNavigate にセットしたパラメータを受け取れるので、src. 4 のように受け取ったパラメータとフィールドに保持したインスタンスを比較した結果を返すよう変更します。

src. 4 のように IsNavigationTarget をデータを判定する処理に変更すると fig. 4 のようにデータに一致した View が表示されるようになります。

fig.4 データに一致した View を表示する

INavigationAware.OnNavigatedFrom イベントでパラメータをセットする

INavigationAware.OnNavigatedFrom イベントは OnNavigatedTo の逆で、現在の View から別の View へ遷移する前(非表示になる前)に呼び出される為、src. 5 のように View に入力された値を Model へ反映することもできます。

OnNavigatedFrom で VM の値を Model へ戻して fig. 5 のような動作にすることもできます。

fig.5 OnNavigatedFrom イベントで値を Model へ戻した場合の動作

このサンプルアプリ内のデータ構造は fig. 6 のようになっていて、TreeViewItem が保持しているデータと編集 View に渡したデータは同一のインスタンスなので、Model へ値を反映すると TreeViewItem の ItemText も fig. 5 のように同時に更新されます。

fig.6 サンプルアプリ内のデータ配置図

但し、現状ではバリデーション等のチェックを何も行っていないため、不正なデータであっても無条件で Model が更新されてしまいます
バリデーションについては又次回以降で紹介する予定です。

OnNavigatedFrom イベントでは src. 5 のように Model へ値を戻す用途だけでなく、次に表示する View へパラメータを渡すこともできますが、このサンプルアプリのように各 View が独立しているような構造のアプリでは有用な例が見つかりませんでした。

ウィザード形式のような画面であれば次に表示する View に渡すデータをセットする等の用途はあると思いますが、パラメータの設定等は episode: 6.5 で紹介している方法をそのまま使用すれば良いはずなので具体例の紹介はしません。

INavigationAware で渡される NavigationContext

INavigationAware の 3 つのメンバ全てに渡される NavigationContext パラメータは値を受け渡しするための Parameters プロパティ以外に NavigationService プロパティも備えています。

NavigationService は IRegionNavigationService 型のプロパティで Journal や Region 等のプロパティを備えていてウィザード形式の画面で使えそうです。
この連載で作成しているサンプルアプリには相性が良くなさそうなので単なる紹介だけにしますが、興味があるなら『Prism.WpfでRequestNavigateと戻る、進む(IRegionNavigationService, IRegionNavigationJournal) – Qiita』で詳しく説明されています。

IRegionMemberLifetime で非 Active になった View を破棄する

INavigationAware.IsNavigationTarget では View の生成 or 再利用 を Prism に指示することができましたが、src. 6 のように IRegionMemberLifetime インタフェースを継承すると View が 非 Active になった際に View を破棄することができます

IRegionMemberLifetime インタフェースの唯一のメンバである KeepAlive 読み取り専用プロパティで false を返すと View が 非 Active になった時にインスタンスが破棄されるようになります。
逆に true を返すと今まで紹介してきた View と同じように非 Active になってもインスタンスは破棄されません。

src. 6 は CategoryPanelViewModel が IRegionMemberLifetime を継承しているので紹介以上の意味はありませんが、毎回表示される度にインスタンスを再生成したい View(VM)で継承します

 

今回は INavigationAware インタフェースと IRegionMemberLifetime を紹介して終了とします。
次回は今回から引き続き RequestNavigate にセットされたパラメータを INavigationAware.OnNavigatedTo で受け取って ReactiveProperty にバインドする方法を紹介します。
今回作成したコードもいつも通り GitHub リポジトリへ上げておきます。

この記事が、2018 年最後の episode になります。
次回は 2019 年 1 月中に公開できれば良いな… と考えています。

 

次回記事「ReactiveProperty がバインドできないのはどう考えても Navigation が悪い!【episode: 8 WPF Prism】」

 

 

おすすめ

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください