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

nuits.jp blog

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

【メモ】PrismでMasterDetailPageと付き合うコツ

そのうち、きっちりまとめ直しますがひとまずメモを。
MasterDetailPageを利用する際に、Prismの画面遷移イベントとライフサイクルイベントをうまく活用するコツをメモっておきます。

MasterDetailPageではDetail側のページを切り替えたり、Detail側にNavigationPageを利用して遷移させたりよくすると思います。
その際に、Prismの画面遷移イベントやライフサイクルイベントを活用するにはいくつかのポイントがあります。
簡単にですが解説と理由を残しておきます。

MasterDetailPageのXAMLにMaster側は一緒に定義し、Detail側は定義しない

つぎのように書くと良いケースが多いでしょう。
MasterDetailPage.Detailが定義されていないところがポイントです。

<?xml version="1.0" encoding="utf-8" ?>
<MasterDetailPage 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="MasterDetailSample.Views.MyMasterDetailPage">
    <MasterDetailPage.Master>
        <ContentPage Title="Master">
            <StackLayout>
                <Button Text="DetailPageA" Command="{Binding NavigateCommand}" />
                <Button Text="DetailPageB" Command="{Binding NavigateCommand}" />
            </StackLayout>
        </ContentPage>
    </MasterDetailPage.Master>
</MasterDetailPage>

Master側をXAMLに定義する理由

ドロワーのメニューを選択した時に、Detail側のPageを切り替えるシナリオがよくあると思います。
この時、MasterDetailPageのViewModelに設定されるINavigationServiceを呼び出す必要があります。

前述のように記述すると、親(つまりMasterDetailPage)のBindingContextを継承するため、Masterに設定されているContentPageからも親のViewModelのプロパティをバインドできるため、便利なケースが多いです。

Detail側をXAMLに定義しない理由

Masterのように親と同じXAMLに定義してしまうと、初期表示時に遷移イベント(OnNavigatedToなど)が呼ばれません。Detailを切り替えると遷移イベントが発生するため処理を共通化するためには、初期表示時も遷移イベントを扱いたいところです。

そこでDetailは未定義にしておいて、MasterDetailPageへ遷移する際につぎのように呼び出しましょう。

navigationService.NavigationAsync("MyMasterDetailPage/NavigationPage/DetailPage");

これで初期表示でDetailPageが初期表示され遷移処理も呼び出されます。

Detailを切り替える時はIDestructibleでリソース解放しよう

リソース解放が必要であれば、ですが。
Detailを切り替えるとPageオブジェクトは一度破棄され、つど再生成されます。
解放が必要なオブジェクトを放置するとリソースのリークが発生するため注意が必要です。

ViewModelにインジェクションしているModelがDI ContainerにSingletonで管理されていて、そのオブジェクトのイベントをReactivePropertyなどで購読していると、購読を明示的に解除しない限り、Detailを切り替えるたびにViewModelのリソースがリークしていきます(よね?多分)。

さいごに

とりあえず、この辺りを押さえておくと、無駄なトラブルを解決できると思います。
ただMasterDetailPageはなんだか色々あるらしいですが…どうなんでしょうね。

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