モバイルの問題

Windows Phone ナビゲーション: 基礎

Yochay Kiriaty

コード サンプルのダウンロード

Silverlight を使用する Windows Phone アプリケーションでは、Web に似たページ モデルを用意して、エンド ユーザーがページ間のナビゲーションを行えるようにしています。Windows Phone には専用のハードウェア "戻る" ボタンがあり、これを使用して (画面領域を操作することなく) 簡単に前のページに戻ることができます。また、ナビゲーションのジャーナル (履歴) はプラットフォームと一体化されるため、異なるアプリケーション間のナビゲーションや切り替えが容易です。この記事は 2 部構成の第 1 部で、次のことについて説明します。

  • Windows Phone のページ ナビゲーション モデルについて紹介します。
  • 最新の API を最大限に活用するために必要なベスト プラクティスについて説明します。ハードウェア "戻る" ボタンの一体化、ページのロードとアンロードの最適化、Windows Phone の認定ガイドラインを満たすナビゲーション モデルなどを紹介します。
  • 一時的なコンテンツ、ページの遷移など、最新の API には実装されていない複雑なナビゲーションを作成する、実用的で使いやすい手法を紹介します。

Windows Phone ナビゲーション モデル

Windows Phone ナビゲーション モデルは、1 つのフレーム (PhoneApplicationFrame) と、そのフレームに読み込まれるコンテンツを保持する 1 つまたは複数のページ (PhoneApplicationPage) から構成されます。

PhoneApplicationFrame は、ナビゲーション イベントの大半と、ページ間を移動する際に使用する Navigate メソッドを公開します。また、アプリケーションのクライアント領域を決定し、アプリケーション バーとシステム トレイ用に領域を確保します。

PhoneApplicationPage には、あるページにナビゲーションを行うときや、ユーザーがあるページから離れるときのためのページ固有の通知があります。また、ハードウェア "戻る" ボタンに関連するイベントも処理します。

PhoneApplicationFrame と PhoneApplicationPage は、実際にナビゲーションを行う NavigationService を共有します。Windows Phone は、ジャーナル (読み込んでいるページの履歴を追跡し、前のページに戻れるようにする機能) をサポートし、API を公開して、ページやアプリケーションを前に戻る操作を実行できるようにしています。携帯電話では、ページやアプリケーションを先に進めるナビゲーションはサポートしません。

Windows Phone には、"戻る"、"スタート"、および "検索" という 3 つの専用ハードウェア ボタンがあります。アプリケーションが認定を受けるときは、ハードウェア "戻る" ボタンの処理に関して、次のような固有の認定要件があります。

  • アプリケーションは、ユーザーが前のページに戻ることを妨げてはなりません。ただし、唯一の例外はデータ損失の可能性がある場合です。その場合は、確認画面を表示して、それでもユーザーがページを戻るかどうかを選択できるようにします。
  • ソフトウェア入力パネル (SIP) やその他の一時ダイアログをポップアップ表示する場合、ハードウェア "戻る" ボタンを押されたら、このダイアログを閉じ、現在のページから移動しないようにします (事実上、"戻る" ボタンはダイアログのキャンセルを行います)。
  • アプリケーションの先頭画面で "戻る" ボタンが押されたら、アプリケーションを終了しなければなりません。この機能は意図しなくても組み込まれます。ユーザーがこのナビゲーションを防がなければ、フレームワークがアプリケーションを終了します。実際のところ、Silverlight アプリケーションを終了する方法は、これしかありません。公開されている API に Exit メソッドはありません。
  • 複数のアプリケーションで一貫したユーザー エクスペリエンス (UX) を確保するには、ページやアプリケーションを前に戻るナビゲーションのみに "戻る" ボタンを使用する必要があります。

ナビゲーションで重要な役割を担う "戻る" ボタンに加えて、"スタート" ボタンもナビゲーションに参加します。ユーザーが "スタート" ボタンを押すと、実行中のアプリケーションが非アクティブになり、コンテキスト切り替えが行われて、スタート メニューに移動します。ここでユーザーは別のアプリケーションを起動し、新しいアプリケーション内にナビゲーションを行うことができます。あるいはここでハードウェア "戻る" ボタンを使用して、以前に実行していたアプリケーションに戻ることもできます。このようにして、"戻る" ボタンを押して、実行中のアプリケーションのページ間や、以前実行していたアプリケーションのスタックの中でナビゲーションを行う効果的なナビゲーション モデルを作成します。

Windows Phone の API

ここまで説明してきたように、ナビゲーションの主役になるのは PhoneApplicationFrame と PhoneApplicationPage です。

PhoneApplicationFrame は、アプリケーションの RootVisual として機能します。起動時、App.xaml.cs ファイルの App クラスで PhoneApplicationFrame のインスタンスを作成します (図 1 参照)。

図 1 App.xaml.cs ファイルでの RootFrame のインスタンス作成

private void InitializePhoneApplication()
{
  if (phoneApplicationInitialized)
        return;

  // Create the frame but don't set it as RootVisual yet; this allows the splash
  // screen to remain active until the application is ready to render.
  RootFrame = new PhoneApplicationFrame();
  RootFrame.Navigated += CompleteInitializePhoneApplication;

           
  // Handle navigation failures
  RootFrame.NavigationFailed += RootFrame_NavigationFailed;

  // Ensure we don't initialize again
  phoneApplicationInitialized = true;
}

ランタイムは、自動的に PhoneApplicationPage のインスタンスにナビゲーションを行います。このことは、次に示すように、WMAppManifest.xml アプリケーション マニフェストの DefaultTask の NavigationPage 属性で指定します。

<Tasks>
  <DefaultTask  Name ="_default" NavigationPage="MainPage.xaml"/> 
</Tasks>

機能と API を少し詳細に見てみると、PhoneApplicationFrame は、この記事で必要なナビゲーションのメソッドやイベントのほとんどを公開しています。図 2 に、PhoneApplicationFrame の関連メソッド、プロパティ、およびイベントを一覧します。

図 2 PhoneApplicationFrame のメソッド、プロパティ、およびイベント

名前 種類 説明
Navigate メソッド URI パラメーターで指定する新しい PhoneApplicationPage にナビゲーションを行います。パラメーターが URI なので、Navigate メソッド呼び出しは、事実上新しいページのインスタンスを作成してそのページにナビゲーションを行います (既にインスタンスを作成しているページは渡しません)。
CanGoBack 読み取り専用プロパティ アプリケーションの戻るスタック (ジャーナル履歴) が空でなければ、true を返します。つまり、ユーザーはアプリケーション内で少なくとも 1 回は次のページにナビゲーションを行っています。アプリケーションに読み込まれた最初のページを表示していれば、CanGoBack メソッドは false を返すため、GoBack メソッドをプログラムから呼び出すことはできません。ただし、エンド ユーザーはハードウェア "戻る" ボタンを押すことができます。この場合、前回実行していたアプリケーションに戻るため、このアプリケーションは終了します。
CanGoForward 読み取り専用プロパティ Windows Phone では意味がありません。先のページに進めるナビゲーションはサポートされないため、常に false が返されます。
UriMapper プロパティ UriMapper プロパティを取得/設定します。ここでは説明の範囲外ですが、URI マッピングがサポートされていることだけお伝えしておきます。
GoBack メソッド 戻るスタックの直前のエントリにナビゲーションを行います。戻るスタックにエントリが存在しないと、例外をスローします。このメソッドを呼び出す前に必ず CanGoForward プロパティをチェックしてください。
GoForward メソッド Windows Phone ではサポートされません。InvalidOperationException をスローします。
Navigating イベント 新しいナビゲーションが要求されると発生します。この時点で、NavigatingCancelEventArgs パラメーターの Cancel プロパティを true に設定することで、そのナビゲーションをキャンセルできます。この後説明しますが、このイベントで戻るナビゲーションをキャンセルしてはいけない理由があることに注意してください。
Navigated イベント ナビゲーションを実行すると発生します。ナビゲーション先のページ コンテンツが読み込み済みとは限りません。単に、コンテンツが見つかってナビゲーションを行ったときに発生します。
NavigationFailed イベント エラーが検出されたときに発生します。
NavigationStopped イベント StopLoading メソッドを呼び出したとき、またはよくあるのが、新しいナビゲーションを要求したもののナビゲーションが実行中だったときに、ナビゲーションが停止すると発生します。

ほとんどが Frame クラスからの継承で、Silverlight の Frame クラスに精通していれば、これらのメソッドには見覚えがあるでしょう。図 2 の一覧は、すべての PhoneApplicationFrame 機能を網羅しているわけではなく、ナビゲーション関連の機能のみに限定しています。

コードの説明: 実際の動作としてこれらのイベントとプロパティをすべて確認するには、この記事付属のサンプル コードの AllNavigationsEvents.xaml.cs ファイルを調べてください。イベントが発生する順序については 図 3 を参照してください。

image: ng>The Sequence of Events as You Navigate Across Pages

図 3 ページ間でナビゲーションを行う際のイベントのシーケンス

PhoneApplicationFrame は、アプリケーションが使用するクライアント領域を決定し、アプリケーション バーとシステム トレイの領域を確保します。この決定と確保がページ単位に指定され、ページが読み込まれるときにアプリケーション バーを表示したり非表示にしたりするシステム単位のアニメーションが存在するため、アプリケーション バーを含むページ間でナビゲーションを行うときは、この詳細がナビゲーションにかかわってきます。

ナビゲーションに関連する 2 つ目の要素が PhoneApplicationPage です。これは、ナビゲーションで次の 2 つの重要な役割を果たします。

  • ハードウェア "戻る" ボタン押下を処理する
  • ページのアクティブ/非アクティブを把握するため、ページのライフサイクルに関するイベントを提供する

ハードウェア "戻る" ボタンを組み込むため、PhoneApplicationPage は BackKeyPress イベントを公開します。また、ページには仮想 OnBackKeyPress メソッドもあり、"戻る" ボタンの押下イベントを処理およびキャンセルする場合は、ページのインスタンスでこのメソッドをオーバーライドできます。

PhoneApplicationFrame には、Navigating イベントと OnNavigatingFrom 通知/コールバックがあります。この両方を使って、アプリケーション内の他のページへのナビゲーションをキャンセルできます。そのためには、これらのメソッドに渡す NavigatingCancelEventArgs パラメーターに e.Cancel = true を設定します。プラットフォームに既知のバグが存在するため、これらのイベント/メソッドからの "戻る" ボタンのナビゲーションをキャンセルしないでください。このイベントでハードウェア "戻る" ボタンの押下をキャンセルすると、ナビゲーションが中断され、アプリケーションの再起動が必要になります。ハードウェア "戻る" ボタンの押下をキャンセルするには、PhoneApplicationPage の BackKeyPress イベントと OnBackKeyPress コールバックの 2 つを使用することをお勧めします。

ナビゲーションをキャンセルできるイベントとメソッドの一覧については、図 4 を参照してください。ここでは、メソッドで "戻る" ボタンの押下をキャンセルできるかどうかに関する推奨事項と、イベントが戻るナビゲーションかどうかをチェックする方法についてのアドバイスを示しています。

図 4 ナビゲーションをキャンセルできるイベントとメソッド

クラス イベント/通知 新しいナビゲーションをキャンセルできる 戻るナビゲーションをキャンセルできる 戻るナビゲーションをチェックする
PhoneApplicationFrame Navigating 不可 可、e.NavigationMode != NavigationMode.Back をチェックする
PhoneApplicationPage OnNavigatingFrom 不可 可、e.NavigationMode != NavigationMode.Back をチェックする
PhoneApplicationPage OnBackKeyPress 不可 ("戻る" ボタン押下時のみ呼び出される) 不要、ハードウェア "戻る" ボタン押下時のみ呼び出される
PhoneApplicationPage BackKeyPress (イベント) 不可 ("戻る" ボタン押下時のみ呼び出される) 不要、ハードウェア "戻る" ボタン押下時のみ呼び出される

PhoneApplicationPage は、有用性の高いページの OnNavigatedTo コールバック メソッドと OnNavigatedFrom コールバック メソッドを使用して、これらのイベントを補完し、ナビゲーションのライフサイクルを管理します。これらのコールバックを呼び出すタイミングを十分に理解し、忘れないようにするには、これらのメソッド名に "このページ" と付け加えて考えることをお勧めします。一方のメソッドはユーザーが「このページにナビゲーションを行った」ときに呼び出され、もう一方のメソッドはユーザーが別のページに「このページからナビゲーションを行った」ときに呼び出されます。

図 3 は、ページ間でナビゲーションを行うときのイベントのシーケンスを示しています。OnNavigatedTo メソッドと OnNavigatedFrom メソッドは対称関係にあるため、ページが表示されるときに必要な操作を開始および停止するのに適しています。ただし、ページが戻るスタックに含まれているときはこのような操作は必要ありません。OnNavigatedTo メソッドは必ずページが読み込まれる前に呼び出されます。そのため、その時点でページのコンテンツが読み込まれているとは想定しないでください。

OnNavigatedTo メソッドと OnNavigatedFrom メソッドが Windows Phone にとって重要なのは、戻るスタックに関係があります。OS は、戻ることができるページを保持する戻るスタックを管理するため、ページ間でナビゲーションが行われると、ページのアンロード、破棄、またはガベージ コレクションをすぐに行いません。代わりに、ページを戻るスタックに追加し、(メモリ内に) 保持します。その後、ユーザーがそのページに戻る操作を行うと、戻り先のページを単純に再びビジュアル ツリーに追加します。ページを作り直すことはありません (ただし、ユーザーがページを離れてから戻る操作を行うまでの間に、アプリケーションが非アクティブになり、トゥームストーン化された場合は除きます)。ページを先に進めるジャーナルはサポートしないため、前のページにナビゲーションが行われると、現在ページが再び表示されることはないと想定し、そのページはガベージ コレクションの対象になります。

図 5 は、PhoneApplicationPage のライフサイクルを示すダイアグラムです。

image: The PhoneApplicationPage Lifecycle

図 5 PhoneApplicationPage のライフサイクル

Page1 から Page2、次に Page3 へとナビゲーションを行うと、いずれかのページから GoBack メソッドを呼び出すまで、ガベージ コレクションは行われません。非アクティブになったページは戻るスタックに追加され、メモリ内に保持されます。これらのページでグローバル イベントを待機していると、イベント リスナーはアクティブなままになります。

ページから離れるナビゲーションを行うと、ガベージ コレクションが実行されないとしても、そのページに戻るまでページは表示されず非アクティブな状態です。そのため、ユーザーがそのページから多くのページにナビゲーションを次々行うと、大量のリソースのクリーンアップや解放を行うことになります。たとえば、GeoCoordinateWatcher メソッドを使用して場所の変化をリッスンしているのであれば、OnNavigatedFrom メソッドでそのリスナーを停止し、ユーザーがそのページに戻ってきた (ページの OnNavigatedTo メソッドが呼び出された) ときにリッスンを再開します。

コードの説明: ページが戻るスタックに含まれている間、メモリ内にどのように保持されているかを確認するには、付属のコード サンプルに含まれる GarbageCollectedSample ページを調べてください。このページは、メモリ内でページの実行記録を管理します。そのため、次のページに移動するとページ数が増加し、前のページに戻ると減少するのがわかります。

以上で、このシリーズの第 1 部は終了です。来月は、高度なナビゲーションに注目します。

Yochay Kiriaty はマイクロソフトのシニア テクニカル エバンジェリストとして、Windows、Windows Phone などのクライアント テクノロジに取り組んでいます。『Introducing Windows 7 for Developers』(Microsoft Press、2009 年) および『Learning Windows Phone Programming』(O'Reilly Media、2011 年) の共著者でもあります。

Jaime Rodriguez はマイクロソフトのプリンシパル エバンジェリストとして、Silverlight、Windows Phone などの新たなクライアント テクノロジの導入に従事しています。Twitter での連絡先は @jaimerodriguez (英語) です。また、blogs.msdn.com/jaimer (英語) にブログを公開しています。

この記事のレビューに協力してくれた技術スタッフの Peter Torr に心より感謝いたします。