nuits.jp blog

C#, Xamarin, WPFを中心に書いています。Microsoft MVP for Development Technologies。

Prism for Xamarin.Forms入門 PushAsync・PopAsyncをViewModelに通知するNavigationPageを作ってみた

さて下記のエントリーで、PrismのINavigationAwareを代替するのに、制限付きではあるもののNavigationPageクラスのイベントを利用できるという紹介をさせていただきました。

www.nuits.jp

今回は実際の実装を見てみたいと思います。 まぁ大したものではないですけど。
それでは早速行ってみましょう。

細かい説明の前に、Github側にコードを公開していますのでそちらを紹介します。

github.com

リンク先のNavigationSample.slnを参照ください。
以下のクラス・インターフェースが対象です。

  1. IPushedAware
  2. IPoppedAware
  3. IPoppedToRootAware
  4. NotifyNavigationPage

Xamarin.FormsではNavigatonPageを利用した画面遷移する際、PageクラスのNavigationプロパティのメソッドを利用します。
それらを利用した際、NavigationPage側のイベントで呼び出しをハンドルすることができます。
以下がその対応表です。

No. メソッド イベント イベント通知ページ
1 PushAsync Pushed Pushされたページ(つまり次のページ)
2 PopAsync Poped Popした側のページ(つまり戻る際の「戻る前」のページ)
3 PopToRootAsync PoppedToRoot Rootページ(つまり一番先頭のページ)

1は2さておき、3を利用するのはちょっと地雷臭がしますよね。
まぁ、「先頭に戻る=状態は全てクリアして良い」でしょうし実害は少ない気もします。

というわけで、実際のコードを順次見ていきましょう。
インターフェースはどれも似たり寄ったりなので、一挙に紹介!

    public interface IPushedAware
    {
        void OnPushed();
    }
    public interface IPoppedAware
    {
        void OnPopped();
    }
    public interface IPoppedToRootAware
    {
        void OnPoppedToRoot();
    }

欲しいイベントに対応するインターフェースをイベントを受け取りたいViewModelでそれぞれ実装するイメージです。
続いてNotifyNavigationPageです。
今回はなんとなくXAMLで書いてみましたが、本来はこのレベルなら普通にcsクラスとして纏めてしまって良いように思います。
とりあえずまずはXAMLから

<?xml version="1.0" encoding="utf-8" ?>
<NavigationPage xmlns="http://xamarin.com/schemas/2014/forms"
                xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
                prism:ViewModelLocator.AutowireViewModel="True"
                x:Class="NavigationSample.NotifyNavigationPage"
                Pushed="OnPushed"
                Popped="OnPopped"
                PoppedToRoot="OnPoppedToRoot">
</NavigationPage>

ページの各イベントに「On〜」イベントハンドラを割り当てています。
次にコードビハインドのコードです。

    public partial class NotifyNavigationPage : NavigationPage
    {
        public NotifyNavigationPage()
        {
            InitializeComponent();
        }

        private void OnPushed(object sender, NavigationEventArgs e)
        {
            (e.Page.BindingContext as IPushedAware)?.OnPushed();
        }

        private void OnPopped(object sender, NavigationEventArgs e)
        {
            (e.Page.BindingContext as IPoppedAware)?.OnPopped();
        }

        private void OnPoppedToRoot(object sender, NavigationEventArgs e)
        {
            (e.Page.BindingContext as IPoppedToRootAware)?.OnPoppedToRoot();
        }
    }

「On〜」イベントハンドラの中では対象のPageのBindingContextがそれぞれ対応するインターフェースを実装していた場合に、対応するメソッドを呼び出します。
これだけです。

さて、画面遷移がらみのイベントハンドリングはもう一つ、以下のエントリーも書いていますので良かったら見てみてください。
どちらかというと、こちらが本命かな?

www.nuits.jp

というわけで、今回はこれまで。
それではまた!