連載
» 2012年09月13日 00時00分 UPDATE

WinRT/Metro TIPS:画面遷移する前の状態を保持するには?[Win 8]

Windowsストア・アプリの画面遷移(ナビゲーション)で、移動前のページを破棄せずに保持しておき、移動先から戻ったきたときに再表示する方法を説明する

[山本康彦,BluewaterSoft]
WinRT/Metro TIPS
業務アプリInsider

powered by Insider.NET

「WinRT/Metro TIPS」のインデックス

連載目次はこちら

 Windowsストア・アプリ(旧称: Metroスタイル・アプリ)の開発で、画面遷移(Windowsストア・アプリでは「(ページ間の)ナビゲーション」と呼ぶ)を、思ったように実装できなくて困ることはないだろうか。特にデスクトップ・アプリの経験者が悩むことが多いようだが、Windowsストア・アプリ独自の実装パターンがあるので、それに逆らわないような作りにするとうまくいく。

 画面を移動するとき、デスクトップ・アプリでは「移動前の画面インスタンスを破棄しないでおいて、移動先の画面から戻って来たときに再び表示させる」という設計がよく行われる。Windowsストア・アプリでも、同じような方法でページの状態を復元できる。そこで本稿では、ページのインスタンスを破棄せずに再利用する方法を説明する。

事前準備

 Windows 8(以降、Win 8)向けのWindowsストア・アプリを開発するには、Win 8とVisual Studio 2012(以降、VS 2012)が必要である。これらを準備するには、第1回のTIPSを参考にしてほしい。本稿ではWin 8とVS 2012 Expressを使用している。

ナビゲーションの実装の基本

 VS 2012のプロジェクト・テンプレートで自動生成されたコードや、MSDNのチュートリアルなどを参考にして、ナビゲーションを実装してほしい。基本は、次に示すコードのようにFrame.Navigateメソッドで移動し、Frame.GoBackメソッドで前のページに戻すようにする。

void ItemView_ItemClick(object sender, ItemClickEventArgs e)
{
  // 適切な移動先のページに移動し、新しいページを構成します。
  // このとき、必要な情報をナビゲーション・パラメータとして渡します
  var itemId = ((SampleDataItem)e.ClickedItem).UniqueId;
  this.Frame.Navigate(typeof(ItemDetailPage), itemId);
}


Private Sub ItemView_ItemClick(sender As Object, e As ItemClickEventArgs)
  ' 適切な移動先のページに移動し、新しいページを構成します。
  ' このとき、必要な情報をナビゲーション・パラメータとして渡します
  Dim itemId As String = DirectCast(e.ClickedItem, Data.SampleDataItem).UniqueId
  Me.Frame.Navigate(GetType(ItemDetailPage), itemId)
End Sub


ほかのページに移動するコード(上:C#、下:VB)
[グリッド アプリケーション (XAML)]プロジェクト・テンプレートで自動生成されたGroupedItemsPage.xaml.cs/.vbファイルの例。


protected virtual void GoBack(object sender, RoutedEventArgs e)
{
  // ナビゲーション フレームを使用して前のページに戻ります
  if (this.Frame != null && this.Frame.CanGoBack) this.Frame.GoBack();
}


Protected Overridable Sub GoBack(sender As Object, e As RoutedEventArgs)
  ' ナビゲーション フレームを使用して前のページに戻ります
  If Me.Frame IsNot Nothing AndAlso Me.Frame.CanGoBack Then
    Me.Frame.GoBack()
  End If
End Sub


前のページに戻すコード(上:C#、下:VB)
同じくLayoutAwarePage.cs/.vbファイルの例。このクラスは、上の「ほかのページに移動するコード」で移動先に指定したItemDetailPageクラスの継承元クラスである。


ページを移動すると状態が失われてしまう問題

 新しく[グリッド アプリケーション (XAML)]プロジェクトを作って、そのまま実行してみてほしい。ここでは分かりやすくするため、次の画像のように最初のページの右上にテキストボックスを追加し、いくつかのアイテムには色を付けた。

dot-winrttips_0004_01a.gif
ほかの画面へ移動して……
dot-down_arrow.gif
dot-winrttips_0004_01b.gif
戻ってくると……
dot-down_arrow.gif
dot-winrttips_0004_01c.gif
初期状態に戻ってしまうナビゲーションの例(VS 2012付属エミュレータ)
最初のGroupedItemsPage(.xamlファイル)でグループ名のところをクリックして2番目のGroupDetailPage(.xamlファイル)に移動し、[戻る]ボタンでGroupedItemsPageに戻ってきたところ。移動する前の状態は失われている。

 VS 2012のプロジェクト・テンプレートのままでは、上の画像のようにほかのページに移動してから戻ってくると、画面は初期状態に戻ってしまう。テキストボックスに入力中だった文字列は失われ、アイテムを表示しているグリッド・ビューのスクロール位置も初期化されてしまう(緑色のアイテムの位置に注目)。

 このとき次の画像のように、最初のページ(GroupedItemsPage.xaml.cs/.vbファイル)でデータを生成しているところ(40行目付近(VBでは20行目付近)のLoadStateメソッド内)にブレイク・ポイントを置いてみると、このページが表示されるたびにデータも取得していることが分かる。戻ってきたときには、内部データも含めて初期化されているのだ。

dot-winrttips_0004_02.gif 最初のページ用のデータを取得しているところにブレイク・ポイントを張る

 このようになるのは、ページが表示されるたびに新しいインスタンスが生成されているからである。ページのインスタンスを破棄せずに使い回すことができれば、解決するだろう。

ページのインスタンスを保持させるには?

 この問題は、次のようにXAMLコードを1行追加するだけで解決できる。

<common:LayoutAwarePage
  x:Name="pageRoot"
  x:Class="MetroTips004.GroupedItemsPage"
  ……中略……
  NavigationCacheMode="Enabled"
  >


GroupedItemsPage.xamlファイルのページの開始タグにNavigationCacheModeプロパティを追加


 上に示したコードのように、そのページの開始タグ(この例では<LayoutAwarePage>要素)にNavigationCacheModeプロパティを追加するだけである。実行してみると、入力中のテキストもスクロール位置も前回と同じで、またブレイク・ポイントで(2回目以降)止まらなくなったことから、一度取得したデータがページ移動によって失われなくなったことが分かる。

 NavigationCacheModeプロパティには、次の3通りの値が設定できる。

  • Disabled : ページのインスタンスをキャッシュしない(デフォルト)
  • Enabled : キャッシュする(サイズが過大になると破棄される)
  • Required : キャッシュする(常に保持される)

 便利な機能ではあるが、メモリ消費が過大になる可能性があるので、その点には注意して使ってほしい。

まとめ

 一度表示したページのインスタンスをキャッシュさせるには、そのページのNavigationCacheModeプロパティを設定すればよい。

 ナビゲーションの設計や実装については、次のURLが参考になる。

「WinRT/Metro TIPS」のインデックス

WinRT/Metro TIPS

Copyright© 1999-2017 Digital Advantage Corp. All Rights Reserved.

@IT Special

- PR -

TechTargetジャパン

この記事に関連するホワイトペーパー

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。