noxi雑記

.NET、Angularまわりの小ネタブログ

Xamarin.FormsとPrismの画面遷移やパラメーターの受け渡し

Xamarin.FormsでPrismを使用する場合、画面遷移はXamarin.Forms組み込みのものでは無く、Prismが提供しているNavigationServiceを使用して画面遷移を行います。その具体的な方法やパラメーターの受け渡しについて説明します。

Xamarin.FormsとPrismの画面遷移やパラメーターの受け渡し

環境について

この記事は以下の環境で動作確認を行っています。

  • Visual Studio 2017 (15.6.6)
  • Xamarin.Forms 2.5.1.444934
  • Prism 7.0.0.396

次の画面に遷移する

PrismにはNavigationServiceという画面遷移を行うためのコンポーネントがあり、Xamarin.Forms元々の画面遷移方法を直接使用せず、NavigationService経由で画面遷移を行います。この画面遷移はWebブラウジングでURLにアクセスしてページを表示するのに似ています。

例えばMainPageからSubPageに画面遷移をする場合、NavigationServiceを使用すると次の様に実装できます。

using Prism.Commands;
using Prism.Mvvm;
using Prism.Navigation;

public class MainPageViewModel : BindableBase
{
    /// <summary>
    /// 画面遷移サービス
    /// </summary>
    private INavigationService NavigationService { get; }

    private DelegateCommand _gotoSubPageCommand;

    /// <summary>
    /// SubPageへ画面遷移するコマンド
    /// </summary>
    public DelegateCommand GotoSubPageCommand
    {
        get
        {
            if (this._gotoSubPageCommand != null)
            {
                return this._gotoSubPageCommand;
            }

            this._gotoSubPageCommand = new DelegateCommand(() =>
            {
                // 3. NavigationServiceのNavigateAsyncメソッドを使用して画面遷移する
                this.NavigationService.NavigateAsync("SubPage");
            });
            return this._gotoSubPageCommand;
        }
    }

    /// <summary>
    /// コンストラクタ
    /// 1. INavigationServiceをDependency Injection(DI)で受け取る。
    /// </summary>
    public MainPageViewModel(INavigationService navigationService)
    {
        // 2. DIで受け取ったINavigationServiceをプロパティに保持
        this.NavigationService = navigationService;
    }
}

XAMLは省略)

1. INavigationServiceをDependency Injection(DI)で受け取る

Prismで画面遷移に使用するNavigationServiceは自分でインスタンス作成する必要はありません。このViewModelの処理に必要なものとしてコンストラクタの引数に記述しておくと、ViewModel生成時にPrismのDIコンテナから自動で取得されます。なお注意点として、NavigationServiceをDIで受け取る時は引数の名前を navigationService にする必要があります。

2. DIで受け取ったINavigationServiceをプロパティに保持

ViewModelの処理に必要なものをコンストラクタの引数として1で受け取りましたが、後々必要なため、プロパティに代入して保持します。

3. NavigationServiceのNavigateAsyncメソッドを使用して画面遷移する

このViewModelのGotoSubPageCommandは、ボタンを押したらSubPageへ遷移する処理が記述されたコマンドです。SubPageへ遷移するにはNavigationServiceのNavigateAsyncメソッドの引数に "SubPage" と遷移先ページ名を文字列で設定します。

次の画面にパラメーター付きで遷移する

画面遷移をするときはただ次の画面を指定するだけでなく、何のアイテムを表示するか等の詳細な情報を付与して遷移したい場合が多々あります。PrismのNavigationServicveはURL遷移と同様にクエリストリングで表示先のページにパラメーターを渡すことができます。例えば次のページに id = 1name = hoge を指定する場合は以下のように記述します。

this.NavigationService.NavigateAsync("SubPage?id=1&name=hoge");

ここで問題が生じます。クエリストリングは?の後に=と&でパラメーターを繋げただけのただの文字列です。次のページに複雑なオブジェクトを渡したい場合はどうすれば良いのでしょうか。
NavigationServiceはクエリストリング以外にも NavigationParameters クラスを使用して画面遷移にパラメーターを付けることができます。先のidとnameをクエリストリングではなくNavigationParametersを使用する場合、以下の様になります。

var p = new NavigationParameters
{
    {"id", "1"},
    {"name", "hoge"},
    {"date", new DateTime()}
};

this.NavigationService.NavigateAsync("SubPage", p);

画面遷移パラメーターを受け取る

ここまででNavigationServiceを使用した画面遷移で、次の画面の指定方法とパラメーターの指定方法を説明しました。次に、遷移先画面で画面遷移パラメーターを受け取る方法を説明します。

Prismで画面遷移パラメーターを受け取るには INavigationAware というナビゲーションイベント時に呼び出されるインターフェースをViewModelに実装します。このインターフェースには3つのナビゲーションイベントに対応するメソッドが定義されています。

メソッド名 説明
OnNavigatingTo この画面に前の(次の)画面から遷移してきた時に、画面表示前に呼ばれるメソッド。
OnNavigatedFrom この画面から次の(前の)画面に遷移する時に呼ばれるメソッド。OnNavigatingToの後に呼ばれる。
OnNavigatedTo この画面に前の(次の)画面から遷移してきた時に、画面表示後に呼ばれるメソッド。OnNavigatedFromの後に呼ばれる。

前のページから渡された画面遷移パラメーターを受け取るには OnNavigatingTo または OnNavigatedTo メソッドの中にその処理を記述します。例えばidとnameを受け取りたい場合は以下のようになります。なお画面遷移時にパラメーターをクエリストリングで指定した場合もNavigationParamtersで指定した場合も、受け取り方は共通です。

public void OnNavigatedTo(NavigationParameters parameters)
{
    var id = (string) parameters["id"];
    var name = (string) parameters["name"];
}

前の画面に戻る

NavigationServiceを使用して前の画面に遷移するには、NavigateAsyncではなく GoBackAsync を使用します。前の画面に戻るコマンドは例えば以下のようになります。

private DelegateCommand _goBackCommand;

public DelegateCommand GoBackCommand
{
    get
    {
        if (this._goBackCommand != null)
        {
            return this._goBackCommand;
        }

        this._goBackCommand = new DelegateCommand(() =>
        {
            this.NavigationService.GoBackAsync();
        });
        return this._goBackCommand;
    }
}

前の画面に戻る時にパラメーターを渡す

前の画面に対して、何らかのパラメーターを渡して戻りたいときがあります。その場合は次のページに遷移するときと同じようにGoBackAsyncにNavigationParametersを渡すことで、前の画面に対してパラメーターを渡すことができます。

private DelegateCommand _goBackCommand;

public DelegateCommand GoBackCommand
{
    get
    {
        if (this._goBackCommand != null)
        {
            return this._goBackCommand;
        }

        this._goBackCommand = new DelegateCommand(() =>
        {
            var p = new NavigationParameters
            {
                {"id", "2"}
            };
            this.NavigationService.GoBackAsync(p);
        });
        return this._goBackCommand;
    }
}

ここで設定した画面遷移パラメーターは、次の画面に遷移するときと同様に、OnNavigatingToまたはOnNavigatedToメソッド内で取得する事ができます。

前の画面に戻る時の画面遷移パラメーターはGoBackAsync以外では OnNavigatedFrom メソッドの引数にあるNavigationParametersに追加が可能です。ただし画面遷移イベントは OnNavigatingToOnNavigatedFromOnNavigetedTo の順に呼ばれるため、GoBackAsyncで設定したパラメーターはOnNavigatingTo、OnNavigatedTo両方で取得する事ができますが、OnNavigatedFromで設定したパラメーターはOnNavigatedToでしか取得出来ません。

NavigationMode

さて、ここまでで画面遷移時のパラメーター受け渡しは進む方向も戻る方向も説明しました。最後に画面遷移が進む方向なのか戻る方向なのか、どちらなのかを判定する方法を説明します。

NavigationParametersには画面遷移パラメーターのほかにひっそりと NavigationMode を持っています。このNavigationModeがNewの時は次の画面への画面遷移、Backの時は前の画面に戻る時の画面遷移です。

public void OnNavigatedFrom(NavigationParameters parameters)
{
    var navigationMode = parameters.GetNavigationMode();
    if (navigationMode == NavigationMode.New)
    {
        // 次の画面へ進む場合
    }
    else
    {
        // 前の画面へ戻る場合
    }
}