読者です 読者をやめる 読者になる 読者になる

nuits.jp blog

C#, Xamarin, WPFを中心に書いています。Microsoft MVP for Visual Studio and Development Technologies。なお掲載内容は個人の見解であり、所属する企業を代表するものではありません。

Prism for Xamarin.Forms入門 ViewModel Firstで画面遷移する

「JXUGC #18 フォローアップハンズオン Prism & Moqをさわってみよう!」で、PrismでのViewModel Firstの実装方法を紹介するといったな?
あれは嘘だ。

って事もないんですけど、調べてみたらコレジャナイ感がありました。
(でもよく考えて一周回って、これでいいのかと思いました)

なお本エントリーは連載記事「Prism for Xamarin.Forms入門」の一部となっております。
以下に目次がありますので、他のエントリーもご覧いただけると嬉しいです。

Prism for Xamarin.Forms入門 目次 - nuits.jp blog

通常、ViewModel Firstで画面遷移するというと、次のようなコードを期待すると思うんですよ。

private void NavigateNext()
{
    var nextPageViewModel = new NextPageViewModel();
    nextPageViewModel.Message = "Hello, Next Page!";
    _navigationService.NavigateAsync(nextPageViewModel);
}

でも実際にPrism製作者が公開している、PrismでViewModel Firstを実践するサンプルコードを利用するとこうなります。

private void NavigateNext()
{
    var parameters= new NavigationParameters();
    parameters["Message"] = "Hello, Next Page!";
    _navigationService.NavigateAsync<NextPageViewModel>(parameters);
}

ちょっと色々言いたいことがある方もいらっしゃるでしょうが(私も言いたいw)、ひとまず実装方法を説明しておきましょう。
まずはNavigationとDIコンテナ関連の拡張メソッド群を用意します。
こちらを参照してください。

https://gist.github.com/brianlagunas/40b8a7d1e25ccc64623b19f11d758171

そしてApp.cs(もしくはApp.xaml.cs)クラスで以下のようにしてViewとViewModelを登録します。

protected override void RegisterTypes()
{
    Container.RegisterTypeForNavigation<NavigationPage>();
    Container.RegisterTypeForNavigation<MainPage>();
    Container.RegisterTypeForViewModelNavigation<NextPage, NextPageViewModel>();
}

今回はNextPageのみをViewModel Firstで遷移できるように登録しています。
従来の方式と混在可能です。

あとは上のコードで画面遷移できます。
簡単ですね。
サンプルプロジェクトはこちらに置いておきます。

https://github.com/nuitsjp/PrimerOfPrismForms/tree/master/03.NavigationService

ViewModelFirstNavigation.slnをご覧ください。

さて、言いたいことコーナーですw

ViewModel First Navigationというと、遷移元で次ページのViewModelの状態を初期化して遷移させるコードを期待する人が多いのではないでしょうか?
そういった期待を持った人からすると、がっかりする方も多いでしょう。
でも私は、実のところこの落としどころは悪くないのではないか?と考えています。

そもそものViewModel Firstの厳密な定義は私も良くわかりません。
しかし、たぶん?本来はViewModel FirstというのはViewよりViewModelを優先して設計・実装しようという意味合いだと思います。
(ここ私の知識が不十分なのでマサカリお持ちの方は投げつけてほしいです)

そこから派生して、次の画面のViewModelを遷移元で初期化して画面遷移するパターンが発生したのではないかと思います。
実のところNavigationServiceのコードを拝借して差し替えれば、Prismで実現するのはそう難しくはありません。

しかし、いくつかの理由からやるべきではないと私は考えています。

  • 改修内容からして今後のPrismのアップデートへの追随が困難になる
  • ViewModel間が密結合になりすぎて変更容易性が大きく失われる

これらの理由から、ViewModel Firstを実践するにしても、前述のサンプルを模倣するのが良いのではないかと私は考えています。
画面遷移間でパラメーターの受け渡しが必要な場合は最低限にして、遷移先でViewModel自身が初期化すべきでしょう。
そもそもModelで共有すべきでパラメーターで渡すべきではないケースも多いはずです。

ということで、なんかあの日の思いとは違った内容になってしまいましたが、ひとまずは以上です。
なお本稿は突っ込みどころが多いため、マサカリは甘んじで受け付けますが、ソフトに投げていただけると死なずに済みます。

それではまた!