それでは、画面遷移をテストしてみよう。デバッグ実行して、イベントハンドラを設定したListViewItemコントロールをタップ/クリックする。想定どおりに2番目の画面に遷移し、2番目の画面で[戻る]ボタンをタップ/クリックすると、メイン画面に戻るはずだ。
スペックを満たした画面遷移ができたようだ。もう一度、今度はメイン画面をスクロールさせてから、同じテストを行ってみよう(次の画像)。
メイン画面に戻ったときに、スクロール状態は初期状態に戻ってしまう。
さてもう一度、今度は2番目の画面を表示しているときに、[デバッグの場所]ツールバー(表示されていないときはメニューバーの[表示]−[ツール バー]−[デバッグの場所]で表示)で[中断とシャットダウン]を選んでデバッグ実行を終了してみる(次の画像)。
この操作は、エンドユーザーがほかのアプリに切り替えたりWindowsをシャットダウンしたりしたときなどに自動的にアプリが終了させられる状況をシミュレートするものだ。デバッグ実行が終了したら、再びデバッグ実行してみよう。すると、メイン画面ではなく、2番目の画面がいきなり表示されるはずだ。そして、[戻る]ボタンが表示されているのでタップ/クリックしてみると、メイン画面に遷移する。これは、自動生成されたSuspensionManagerクラス(=Commonフォルダ内の「SuspensionManager.cs」ファイル)の機能である。画面遷移の履歴を自動的に保存し、次の起動時に復元してくれるのだ*4。
*4 これが機能するのは、プロジェクトを作るときに、[グリッド アプリケーション (XAML)]や今回のように[ハブ アプリ (XAML)]などを選んだ場合だ。[新しいアプリケーション (XAML)]から始めた場合は機能しない。
では、メイン画面に帰ってくるとスクロール状態が元に戻ってしまった問題に戻ろう。これはスペックを検討したときに気付かなかったことだ。なぜこうなるのか、また、どう対処すべきなのだろうか?
この現象は、画面遷移すると元の画面のインスタンスが破棄されるために起きている。2番目の画面に遷移したときに元のメイン画面のインスタンスは捨てられてしまい、[戻る]ボタンで遷移するときにメイン画面のインスタンスが新しく生成されているのだ。
「画面遷移で元の画面は捨てられる」、このことはよく覚えておいてほしい。
さて、どう対処すべきだろう。まず、再び表示したときに以前と同じ状態になっているべきかという、スペックの問題だ。次に、状態を復元すべきとなったときには、どうやってそれを実現するかという、実装の問題になる。
スペックを考えてみると、2番目の画面では再表示時に初期化されても構わないだろう。メイン画面で記事タイトルをタップ/クリックして記事を読みにいくときに、前回読んだときのスクロール位置が再現されると期待するユーザーはそれほどいないだろうからだ。対してメイン画面は、再表示時に以前の状態が復元されるべきだろう。特にメイン画面の右の方の記事タイトルを読みにいって、帰ってきて次の記事を読もうとしたときにまたメイン画面の右の方までスクロールするのはストレスを感じるだろう。
そこでこのアプリでは、メイン画面だけ状態を復元することにしよう。その実装方法には、2通りある(次の表)。
概要 | 説明 |
---|---|
画面のインスタンスをキャッシュさせる | デフォルトでは画面遷移時に画面のインスタンスは破棄されてしまうが、PageオブジェクトのNavigationCacheModeプロパティによりメモリ上に保持できる。 容易だが、メモリ使用量を気にしなければならないし、アプリの再起動時には復元されない。 詳しくは「WinRT/Metro TIPS:画面遷移する前の状態を保持するには?[Win 8]」を参照 |
SuspensionManagerクラスが管理しているPageStateオブジェクトを利用する | PageStateオブジェクトにセットしたデータは自動的に維持される(アプリが強制終了/異常終了しない限り)。そこで、画面の状態を復元するために必要な情報をPageStateオブジェクトに保存しておき、画面が表示されるときにその情報を使って復元する。 面倒だが、アプリの再起動時にも復元される。 詳しくは「WinRT/Metro TIPS:起動時に以前の画面を復元するには?[Win 8]」を参照(ただし、「SaveState」→「navigationHelper_SaveState」、「LoadState」→「navigationHelper_LoadState」と読み替えてほしい*5) |
画面の再表示時に以前の状態を復元する方法 |
*5 Win 8.1アプリでは、「navigationHelper_SaveState」と「navigationHelper_LoadState」の2つのイベントハンドラは自前で登録しなければならない(Win 8アプリでは「LayoutAwarePage」クラスに実装されていた)。今回作ったViewPageクラス(=「ViewPage.xaml.cs」ファイル)のコンストラクタを参照。また、プロジェクトを作るときに、[グリッド アプリケーション (XAML)]や今回のように[ハブ アプリ (XAML)]などを選んだときはよいのだが、[新しいアプリケーション (XAML)]から始めた場合はこの機能は利用できない(必要なファイルがCommonフォルダに生成されないし、Appクラスにもコードが不足している)。
本アプリでは、1番目の方法を採用しよう。「HubPage.xaml」ファイルを開いて、最初の開始タグに1行追加するだけだ(次のコード)。
<Page
x:Name="pageRoot"
x:Class="AtmarkItReader.HubPage"
……省略……
mc:Ignorable="d"
NavigationCacheMode="Required"
>
これでテストをやり直してみよう。今度は、2番目の画面に行って帰ってきたときにメイン画面のスクロール状態が復元されるはずだ。
今回は、2つ目の画面を作り、メイン画面からの画面遷移を組み込んだ。画面遷移のスペックを決める際には、再表示のときにどうするかの検討も必要だと学んだ。
次回は「データを画面に表示する」。ここまで、画面にはハードコーディングした文字列などを表示してきた。次は、「データバインディング」という仕組みを使って、コードとは別に用意したデータを画面に表示できるようにする予定だ。期待してほしい。
Copyright© Digital Advantage Corp. All Rights Reserved.