かずきのBlog@hatena

すきな言語は C# + XAML の組み合わせ。Azure Functions も好き。最近は Go 言語勉強中。日本マイクロソフトで働いていますが、ここに書いていることは個人的なメモなので会社の公式見解ではありません。

KAMISHIBAI for Xamarin.Forms を Prism で使ってみよう

nuitsさんが面白そうなものを作ってました。

www.nuits.jp

さて、個人的に気になるのは Prism と組み合わせた場合の方法。なんたって Prism にも組み込みの画面遷移機能があるので。

考えたこと1

Prism の画面遷移機能は原理的に画面遷移を行うための機能を提供する INavigationService の実装を完全に差し替える機能が提供されています。 これを使えば KAMISHIBAI for Xamarin.Forms を内部で使うようにした INavigationService を作れるのでは?と思いました。

んで、具体的に考え始めたら破綻しました。はい。

KAMISHIBAI for Xamarin.Forms は、ViewModel で画面遷移のきっかけを発火するための INavigationRequest がいて、実際にどうやって画面遷移するのかは Behavior でやるというアプローチです。 画面遷移先が複数ある場合は INavigationRequest を遷移先の数だけ ViewModel に生やして、それに対応する Behavior を View に定義するといった形になるっぽいですね。

単一の INavigationService でやるのはちょっとしんどそう。

考えたこと2

画面遷移処理の実態は Behavior でやってます。 つまり、INavigationRequest のイベントを購読して画面遷移処理自体は Prism の INavigationService を使うような Behavior を作ってやれば…!?

KAMISHIBAI for Xamarin.Forms の画面遷移処理を行う Behavior は x:TypeArguments で遷移先のページを指定します。 これが多分キモっぽい気がするので、これを殺した Behavior を作って嬉しいかな?という疑問が浮かんできたのと、Behaviorで、どうやって Prism の INavigationService のインスタンスを綺麗に取得するのか?というのところがめんどくさくてやめました。

やったこと

Prism の画面遷移機能は使わない。 KAMISHIBAI for Xamarin.Forms で置き換えました。

つまり、App.xaml.csは以下のような感じになります。

using Autofac;
using Kamishibai.Xamarin.Forms;
using Prism.Autofac;
using Prism.Autofac.Forms;
using Prism.Navigation;
using PrismAutofacApp2.Views;
using Xamarin.Forms;

namespace PrismAutofacApp2
{
    public partial class App : PrismApplication
    {
        public App(IPlatformInitializer initializer = null) : base(initializer) { }

        protected override void OnInitialized()
        {
            InitializeComponent();

            ApplicationService.Initialize(this);
            ApplicationService.SetMainPage(new NavigationPage(new MainPage()));
        }

        protected override void RegisterTypes()
        {
        }
    }
}

View と ViewModel の紐づけは ViewModelLocator を使ってやるところは変わりありません。

あとは、サンプルにある通り KAMISHIBAI を使えばOKです。

使えなくなる Prism の機能

KAMISHIBAI for Xamarin.Forms は、Viewにデフォルトコンストラクタがあることを前提に作られています。 Prism の画面遷移機能を使うと View のインスタンスもDIコンテナから取得するので、Viewにたいしても色々インジェクションできますが、これが使えなくなります。

まぁ実際問題Viewにインジェクションすることってあるか?という問題があるので実質問題にならないかもですね。

もしかしたら、IEventAggregatorのイベントを View で購読したいってことがあるかも??(やったことはない)

あとは、パス指定一発で深いページに飛ぶってことが出来なくなりますね(/NavigationPage/TabbedPage/MainPage?id=10みたいな)。 これはちょっと痛いかも。外部アプリから起動されたときや、サスペンドからの復帰のときとかに一気にどかっとページのスタックを復元する(しかもパラメータつきで)のがめんどくさくなりそうな気がします。

楽になるところ

Prism は View のクラスを追加するたびに RegisterTypeForNavigation メソッドでDIコンテナに View を登録しないといけませんでした。 そうしないと、DIコンテナから取得できないので。

KAMISHIBAI for Xamarin.Forms を使うと遷移先は遷移元のページの Behavior に型引数として定義するのでいらなくなりますね。

まとめ

とまぁ使ってみましたが Prism から画面遷移機能を抜くと DelegateCommand, BindableBase, EventAggregator, PageDialogService, DIサポート, ちょっと便利なビヘイビアー(ここはnuitsさんのリリースしてるBehaviorのパックのほうが便利…)なので、どれくらい使う価値があるかっていうのも再考がいりそうですね。

個人的にDIとPageDialogServiceは欲しいですね。