Xamarin.FormsでViewModelを使っている場合、そのページが破棄されたタイミングでイベントの購読解除等を行うDispose的な処理を書きたいなと思っていてその方法を調べてみました。
ページが破棄されるのをStackからページがPopされることとすれば、Popに関するイベントを捉えるのが良さそうです。
調べてみるとPushAsyncはNavigationPageのPoppedイベント、PushModalAsyncはApplication.CurrentのModalPoppedイベントで対処できるようです。
ViewModelに適当なインターフェースを適用する
例としてIDisposableを適用。自作インターフェースでももちろん可。
public class ViewModelSample : IDisposable
{
public void Dispose(){
//後始末
}
}
NavigationPageのPoppedに登録
PopAsyncでPopしたページはNavigationPageのPoppedイベントで拾えるのでNavigationPageのコンストラクタ等で処理を登録しておきます。毎回書くのがめんどうならBaseクラスにでも。
public MainNavi() {
this.Popped += (sender, e) => {
(e.Page.BindingContext as IDisposable)?.Dispose();
};
}
Application.CurrentのModalPoppedに登録
PopModalAsyncでPopしたページはApplication.CurrentのModalPoppedイベントで拾えるのでAppクラスのコンストラクタ等で処理を登録しておきます。
public App(){
Application.Current.ModalPopped = (sender, e) => {
(e.Modal.BindingContext as IDisposable)?.Dispose();
};
}
注意事項
PopToRootAsyncを使うと処理対象のページを見失います。
PoppedToRootイベントで拾えそうなんですが、そこで拾えるのは直前のページだけで他のページは参照できません。しかもPoppedToRootはPopした後なのでNavigationStackにも残ってません。なのでPopと特定の処理を合わせたい場合はPopToRooTAsyncは使わないようにするか、同様の動きをする機能を独自に実装するしかないと思います。
補足
iOSではTabbedPageの現在表示中のタブをクリックするとルートページに戻ります。これはPopToRootしているように見えますが実際は1ページずつPopしているようなのでPoppedイベントの方で処理できます。
参考