ViewModelのTombstonedの処理について
Windows Phone SDK 7.1からTombstonedに加えDormantという状態が加わったためページを復元する処理がややこしくなりました。そこでViewModelを保存し復元するときの注意点をまとめてみました。
その前にTombstonedやDormantについて知りたい方はこちらの記事を参考にしてください。
Tombstoned(トゥームストーン)とDormant(ドーマント)について
Tombstonedのときはアプリケーションとページの2つの状態を保存し復元することを考慮する必要がありますが、ここではページの状態についての説明します。
保存のタイミング
OnNavigatedFromメソッドでページを離れるときにページの状態を保存します。
private ViewModel _viewModel; protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e) { if (e.NavigationMode != System.Windows.Navigation.NavigationMode.Back) { State["ViewModel"] = _viewModel; } }
SDK 7.1からOnNavigatedToとOnNavigatedFromの引数に渡ってくるNavigationEventArgsにNavigationModeが追加されました。これはナビゲーションの種類を表します。
NavigationMode | 説明 |
---|---|
New | 新規にページが開かれるとき(NavigateメソッドやSourceメソッドを呼ぶ) |
Back | 戻るボタン(GoBackメソッド)を呼ぶとき |
Forward | GoForwardメソッドを呼ぶとき(Windows Phoneでは使わない) |
Refresh | Refreshメソッドを呼ぶとき(Windows Phoneでは使わない) |
ViewModelを保存するのは戻るボタン(あるいはGoBackメソッド)を押した時以外にページを去るときです。たとえばTaskやChooserを起動したりスタートボタンを押す時です。*1戻るボタンを押したときはこのページは破棄されるのでデータを復元する必要がないため保存する処理を行いません。
復元するタイミング
OnNavigatedToでページの状態を復元します。
復元するときはさまざまなことを考慮しなければなりません。
- 新規のページとして表示するのか?それとも以前の状態を復元するのか?
- このページは新しく生成されたのか?それとも以前のページなのか?
これらのことを考慮しなければならないため処理が複雑になりがちです。しかし考慮すべきことは決まっているのでOnNavigatedToで行う処理は下記のようにパターン化することができます。
bool _isNewPageInstance = false; public コンストラクタ() { InitializeComponent(); _isNewPageInstance = true; // 新たにページが生成されるときはtrueに設定する } protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e) { if (_isNewPageInstance) { // _viewModelがnullのときは、新規でデータを作るとき // _viewModelがnullでない場合は、データを編集するページのように予めこのページで表示する値が設定されているとき if (_viewModel == null) { if (State.Count > 0) { // ViewModelの復元 _viewModel = State["ViewModel"] as ViewModel; } else { // ViewModeの初期化 _viewModel = new ViewModel(); } } DataContext = _viewModel; } // Stateの削除 if (State.ContainsKey("ViewModel")) State.Remove("ViewModel"); _isNewPageInstance = false; // 元に戻す base.OnNavigatedTo(e); }
_isNewPageInstance変数について
_isNewPageInstance変数はページが新たに生成されたかどうかを表す変数です。メモリ上にページが残っている場合はこのフラグはfalseになり、新たにページが作られるときはこのフラグがtrueになります。
■新たにページが作成されるとき
- Navigateされたとき
- Tombstonedのとき
これらのときには_isNewPageInstance変数にtrueがコンストラクタで設定されます。
■ページが生成されないとき
- アプリケーション内で戻るボタンを押した時
- DatePickerやListPickerなどのコントロールから戻ってきた時
- TaskやChooserから戻ってきた時
- Dormantのとき
これらのときはメモリ上にページが存在するので_isNewPageInstance変数にfalseが設定されます。
_isNewPageInstance変数がtrueのときは初期化あるいは復元の処理が必要であり、_isNewPageInstanceがfalseのときはなにもする必要がありません。
このようにWindows Phone上ではさまざまな状態を考慮する必要があります。
*1:TaskやChooserのときはページがメモリ上に残っているのでViewModelを保存する必要はありませんが、その判断が付かないため保存しています