LoginSignup
8

More than 5 years have passed since last update.

Xamarin.Formsでページが破棄されたタイミングでViewModelのDisposeなどを実行する

Last updated at Posted at 2016-06-20

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イベントの方で処理できます。

参考

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8