画面遷移の履歴を削除するには?[ユニバーサルWindowsアプリ開発]:WinRT/Metro TIPS
多段階の画面遷移を行うユニバーサルアプリで、画面遷移の履歴を削除する方法を解説する。
powered by Insider.NET
[戻る]ボタンで遷移する先の画面を制御したいと思ったことはないだろうか? 例えば、1つ前の画面を飛ばして、もう1つ前の画面に戻したい、といった場合だ。ユニバーサルWindowsアプリでは、画面遷移の履歴が自動的に記憶されるようになっている。その履歴を操作することで、戻り先の画面を変更できるのだ。
そこで本稿では、画面遷移の履歴の全部または一部を削除する方法を解説する。なお、本稿のサンプルは「Windows Store app samples:MetroTips #93」からダウンロードできる。
事前準備
ユニバーサルプロジェクトを使ってユニバーサルWindowsアプリを開発するには、以下の開発環境が必要である。本稿では、無償のVisual Studio Express 2013 for Windowsを使っている。
- SLAT対応のPC*1
- 2014年4月のアップデート*2適用済みの64bit版Windows 8.1 Pro版以上*3
- Visual Studio 2013 Update 2(またはそれ以降)*4を適用済みのVisual Studio 2013(以降、VS 2013)*5
*1 SLAT対応ハードウェアは、Windows Phone 8.1エミュレーターの実行に必要だ。ただし未対応でも、ソースコードのビルドと実機でのデバッグは可能だ。SLAT対応のチェック方法はMSDNブログの「Windows Phone SDK 8.0 ダウンロードポイント と Second Level Address Translation (SLAT) 対応PCかどうかを判定する方法」を参照。なお、SLAT対応ハードウェアであっても、VM上ではエミュレーターが動作しないことがあるのでご注意願いたい。
*2 事前には「Windows 8.1 Update 1」と呼ばれていたアップデート。スタート画面の右上に検索ボタンが(環境によっては電源ボタンも)表示されるようになるので、適用済みかどうかは簡単に見分けられる。ちなみに公式呼称は「the Windows RT 8.1, Windows 8.1, and Windows Server 2012 R2 update that is dated April, 2014」というようである。
*3 Windows Phone 8.1エミュレーターを使用しないのであれば、32bit版のWindows 8.1でもよい。
*4 マイクロソフトのダウンロードページから誰でも入手できる(このURLはUpdate 3のもの)。
*5 本稿に掲載したコードを試すだけなら、無償のExpressエディションで構わない。Visual Studio Express 2013 with Update 3 for Windows(製品版)はマイクロソフトのページから無償で入手できる。Expressエディションはターゲットプラットフォームごとに製品が分かれていて紛らわしいが、Windowsストアアプリの開発には「for Windows」を使う(「for Windows Desktop」はデスクトップで動作するアプリ用)。
用語
本稿では、紛らわしくない限り次の略称を用いる。
- Windows:Windows 8.1とWindows RT 8.1(2014年4月のアップデートを適用済みのもの)
- Phone:Windows Phone 8.1
サンプルコードについて
Visual Studio 2013 Update 2(およびUpdate 3)では、残念なことにVB用のユニバーサルプロジェクトのテンプレートは含まれていない*6。そのため、本稿で紹介するコードはC#のユニバーサルプロジェクトだけとさせていただく*7。
*6 VB用のユニバーサルプロジェクトは、来年にリリースされるといわれているVisual Studio「14」からの提供となるようだ。「Visual Studio UserVoice」(英語)のリクエストに対する、6月18日付けの「Visual Studio team (Product Team, Microsoft)」からの回答による。
*7 Visual Studio 2013 Update 2(またはUpdate 3)のVBでユニバーサルWindowsアプリを作る場合のお勧めは、「The Visual Basic Team」のブログ記事(英語)によれば、PCLを使う方法のようである。しかし、本稿で説明するような画面遷移関連のコードをPCLに置くことは非常に困難である(PCLから画面に直接アクセスできないためであり、絶対に不可能というわけではない)。
画面遷移の履歴を削除したいケース
どんなときに画面遷移の履歴を削除したくなるだろうか? 2つほど例を挙げておく。
1つは、画面遷移の階層が深い場合だ。メイン画面(=アプリ起動時に表示される画面)から画面遷移を2〜3回以上繰り返して到達する画面の場合、エンドユーザーの利便性を考えると、直接メイン画面に移動するボタンを設置したい。そのボタンで普通にメイン画面へ遷移すると、Windowsではメイン画面に[戻る]ボタンが表示されてしまうのだ(次の図)。
メイン画面へ遷移すると、メイン画面に[戻る]ボタンが表示されてしまう
深い階層の画面で、エンドユーザーの利便性のためにメイン画面へ移動するボタンを付けることがある。この図の[サブ画面2]にいるとき、メイン画面に戻るには[戻る]ボタンを2回タップしないといけない。あるいは、エンドユーザーは現在位置を見失っていて、メイン画面に戻る方法が分からないかもしれない。そこで、この[サブ画面2]に、メイン画面へ直接移動するボタンを設置したとする。すると、メイン画面に遷移させたときに、Windowsでは[戻る]ボタンが表示されてしまう(赤丸内)。Phoneでは、デバイスの[戻る]ボタンでスタート画面に戻らず、[サブ画面2]に戻ってしまうのだ。
メイン画面に[戻る]ボタンが表示されるのが良いか悪いかは、UX(ユーザー体験)の設計次第ではある。ここでは、表示したくないものとして、その手段を考えることにしよう。
もう1つの例は、エラー画面を出す場合だ。アプリの処理中に出たエラーをエンドユーザーに報告する画面を作ることがある。そのエラーを報告する画面で[戻る]ボタンをタップされたときは、どの画面に戻るべきだろうか? あるいは、エラー画面から別の画面に遷移したとき、その画面からの戻り先はどこにすべきだろうか? このような場合、エラーを起こした画面とエラー画面は、戻り先から外したいだろう(次の図)。
エラー報告画面を出した場合、戻り先の画面はどこにすべきだろうか?
この図の例では、[画面A]から[画面B]に遷移し、[画面B]の処理中に何らかの例外が発生した場合を想定している。そして、例外をトラップして[エラー画面]に遷移させ、エラーの内容をエンドユーザーに報告するようにしたとする。この場合、[エラー画面]から戻る先は[画面B]でよいだろうか? それでは再び同じ例外が発生する可能性が高いので、エンドユーザーにやり直してもらうなら少なくとも[画面A]まで戻すべきだろう。また、[エラー画面]から[画面C]に遷移させた場合、[画面C]から戻る先が[エラー画面]ではおかしいだろう。この場合も、[画面A]まで戻した方がよさそうである。
画面遷移の履歴を全て削除するには?
画面遷移の履歴は、Frameコントロール(Windows.UI.Xaml.Controls名前空間)のBackStackプロパティに保持されている。履歴を全て削除するには、BackStackプロパティのClearメソッドを呼び出せばよい。
最初の図の例では、メイン画面に遷移してきたときに履歴を全て削除してしまえばよい。それには、メイン画面のOnNavigatedToメソッドをオーバーライドして、次のようなコードを記述する。
protected override void OnNavigatedTo(NavigationEventArgs e)
{
……省略(既存のコード)……
// メイン画面に遷移してきたときは、常にBackStackプロパティをクリアする
this.Frame.BackStack.Clear();
}
このコードは、ユニバーサルプロジェクトを作成するときに[ハブ アプリケーション]テンプレートを選び、追加するページには[基本ページ]テンプレートを選んで試してほしい([空のアプリケーション]テンプレートや[空白のページ]テンプレートでは、[戻る]ボタンとそれを制御するコードが含まれないので、このコードの効果も分からない)。
なお、別途公開のサンプルコードでは、このコードを含む画面のコードビハインドを共有プロジェクトの「View」フォルダーに置き、画面のXAMLファイルはWindows/Phoneそれぞれのプロジェクトの「View」フォルダーに配置してある(以下同じ)。
これによって、メイン画面を表示したときには常に画面遷移の履歴が存在しない状態になり、[戻る]ボタンは表示されなくなる。
画面遷移の特定の位置の履歴だけを削除するには?
特定の位置の履歴だけを削除するには、BackStackプロパティのRemoveAtメソッドを使えばよい。保持されている履歴の個数は、FrameコントロールのBackStackDepthプロパティで取得できる。
2つ目の図の例で、[エラー画面]から[画面C]に遷移させる部分でやってみよう。[エラー画面]のClickイベントハンドラーで、[画面C]に遷移させてから履歴の末尾を削除する(次のコード)。
private void NavigateC_Click(object sender, RoutedEventArgs e)
{
// [画面C]に遷移させる
this.Frame.Navigate(typeof(PageC));
// Navigateメソッドを呼ぶと、現在表示されていた画面(=[エラー画面])がBackStackプロパティに入る
// BackStackプロパティの末尾を1つ削れば、この画面を表示したという履歴は消える
this.Frame.BackStack.RemoveAt(this.Frame.BackStackDepth - 1);
}
[エラー画面]のボタンのClickイベントハンドラーを、このように記述する。
履歴を削除しているのは、太字にした部分だ。
画面遷移してから履歴を削除しないといけないことに、注意してほしい。現時点で表示されている画面は履歴に入っていないのだ。FrameコントロールのNavigateメソッドを呼び出して画面遷移させたときに、表示されていた画面が履歴に入るのである。
これにより、[エラー画面]から[画面C]に遷移したとき、画面の履歴から[エラー画面]が消える。すると、[画面C]で[戻る]ボタンをタップしたときに、[エラー画面]は飛ばされて、その前の画面が表示されるのである。
なお、2つ目の図の例で、エラーを捕捉して[エラー画面]を表示する部分も、別途公開のサンプルコードには実装してある。参考にしていただきたい(「App.xaml.cs」ファイル内)。そこでは、[エラー画面]に遷移させたときに、履歴から直前の[画面B]を削除している(従って、上のコードと合わせて、[画面C]の[戻る]ボタンで[画面A]まで戻るようになっている)。
画面遷移の特定の画面の履歴を削除するには?
図に示した例には含まれていないが、特定の画面の履歴を削除する方法も解説する。
BackStackプロパティは、PageStackEntryオブジェクト(Windows.UI.Xaml.Navigation名前空間)のリストになっている。PageStackEntryオブジェクトのSourcePageTypeプロパティには表示していた画面の型(=System名前空間のTypeクラス)が入っているので、どの画面を表示したときの履歴であるか判別できる。
複数の画面を指定して、それらの画面を表示した履歴を全て削除したいとしよう。次のコードのようなメソッドにまとめられる。
public static void RemoveHistories(Windows.UI.Xaml.Controls.Frame frame, IList<Type> pages)
{
// リストから複数のアイテムを削除するときは、後ろから行うと簡単である
for (var index = frame.BackStackDepth - 1; index >= 0; index--)
{
var entry = frame.BackStack[index]; // PageStackEntryオブジェクトを1つ取り出し、
if (pages.Contains(entry.SourcePageType)) // それが指定された画面と一致するなら、
frame.BackStack.RemoveAt(index); // 履歴から削除する
}
}
別途公開のサンプルコードでは、共有プロジェクトの「NavigationHistoryManager.cs」ファイルに記述してある。
まとめ
画面遷移の履歴を全て消すには、FrameコントロールのBackStackプロパティのClearメソッドを呼び出せばよい。特定の位置の履歴を消すには、BackStackプロパティのRemoveAtメソッドを使う。特定の画面の履歴を消したいときには、BackStackプロパティのリストに入っているPageStackEntryオブジェクトのSourcePageTypeプロパティを使って、該当する履歴を見つけ出す。なお、現在表示している画面はBackStackプロパティに入っていないので、間違えないようにしよう。
Copyright© Digital Advantage Corp. All Rights Reserved.