セカンダリタイルからアプリを起動した場合などに、ページを楽に移動できるように、画面遷移の履歴を追加する方法を解説する。
powered by Insider.NET
前回は、画面遷移の履歴を削除する方法を紹介した。逆に、画面遷移の履歴を追加/挿入したいことはないだろうか? 例えば、セカンダリタイルから起動したときに遷移先の画面を表示することがある。そのとき、[戻る]ボタンを表示してメイン画面に戻れるようにしたい、といった場合だ。そこで本稿では、画面遷移の履歴を追加する方法を解説する。なお、本稿のサンプルは「Windows Store app samples:MetroTips #94」からダウンロードできる。
ユニバーサルプロジェクトを使ってユニバーサルWindowsアプリを開発するには、以下の開発環境が必要である。本稿では、無償のVisual Studio Express 2013 for Windowsを使っている。
*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 4のもの)。
*5 本稿に掲載したコードを試すだけなら、無償のExpressエディションやCommunityエディションで構わない。Visual Studio Express 2013 with Update 4 for Windows(製品版)はマイクロソフトのページから無償で入手できる。Expressエディションはターゲットプラットフォームごとに製品が分かれていて紛らわしいが、Windowsストアアプリの開発には「for Windows」を使う(「for Windows Desktop」はデスクトップで動作するアプリ用)。また、この11月12日(米国時間)に新しくリリースされたVisual Studio Community 2013 with Update 4(製品版)もマイクロソフトのページから無償で入手できる。Communityエディションは本稿執筆時点では英語版だけなので、同じ場所にあるVisual Studio 2013 Language Packの日本語版を追加インストールする必要がある。
本稿では、紛らわしくない限り次の略称を用いる。
Visual Studio 2013 Update 2(Update 3/4も)では、残念なことにVB用のユニバーサルプロジェクトのテンプレートは含まれていない*6。そのため、本稿で紹介するコードはC#のユニバーサルプロジェクトだけとさせていただく*7。
*6 VB用のユニバーサルプロジェクトは、来年にリリースされるといわれているVisual Studio 2015(開発コード「Visual Studio 14」)からの提供となるようだ。「Visual Studio UserVoice」(英語)のリクエストに対する、6月18日付けの「Visual Studio team (Product Team, Microsoft)」からの回答による。
*7 Visual Studio 2013 Update 2以降のVBでユニバーサルWindowsアプリを作る場合のお勧めは、「The Visual Basic Team」のブログ記事(英語)によれば、PCLを使う方法のようである。しかし、本稿で説明するような画面遷移関連のコードをPCLに置くことは非常に困難である(PCLから画面に直接アクセスできないためであり、絶対に不可能というわけではない)。
セカンダリタイルから起動できるアプリでは、メイン画面(=アプリ起動時に表示される画面)に戻れない(あるいは、戻る手順が複雑になる)場合がある。そこで画面遷移の履歴にメイン画面を追加できれば、[戻る]ボタンですぐにメイン画面に戻れるようになる。
例えば、前回のサンプルコードでは、[メイン画面]→[画面A]→[画面B]→[画面C]→[メイン画面]という画面遷移を行った(エラー時の画面遷移は除く)。そこにセカンダリタイルから起動する機能を追加し、[画面A]を直接表示できるようにしてみよう(次の図)。すると、セカンダリタイルから起動したときの[画面A]は、Windowsでは[戻る]ボタンが表示されず、Phoneでは[戻る]ボタンのタップでスタート画面に戻ってしまう。
セカンダリタイルから[画面A]を直接開くと、[メイン画面]に戻るのが困難になる
セカンダリタイルからの起動時、単純に[画面A]を表示させた場合。Windowsでは[画面A]に[戻る]ボタンが表示されず、Phoneでは[戻る]ボタンをタップするとスタート画面に戻ってしまう。「[メイン画面]から遷移してきた」という履歴がないためである。この例では[画面C]まで進めば[メイン画面]へ遷移するボタンが使えるが、そうでなければ[メイン画面]を表示する手段がなくなってしまう。
セカンダリタイルからの起動時に「[メイン画面]を表示した」という仮想的な履歴を追加できれば、この問題は解決するだろう。
アプリからセカンダリタイルを作成できるようにするには、次のようなコードを記述する(このコードだけでは、作成したセカンダリタイルから起動しても[メイン画面]が表示されるだけである)。
private async void SetTile_Click(object sender, RoutedEventArgs e)
{
// セカンダリタイルの生成
// (簡易的に、固定IDのタイルを生成するだけ)
const string TileId = "MetroTips094.PageA";
if (!Windows.UI.StartScreen.SecondaryTile.Exists(TileId))
{
var secondaryTile
= new Windows.UI.StartScreen.SecondaryTile(
tileId: TileId,
displayName: "WinRT/Metro TIPS #094 Page-A",
arguments: "PageA", // (1)
square150x150Logo: new Uri("ms-appx:///Assets/Logo.png"),
desiredSize: Windows.UI.StartScreen.TileSize.Square150x150
);
secondaryTile.VisualElements.BackgroundColor
= Windows.UI.Colors.Orange;
secondaryTile.VisualElements.ForegroundText
= Windows.UI.StartScreen.ForegroundText.Dark;
secondaryTile.VisualElements.ShowNameOnSquare150x150Logo = true;
await secondaryTile.RequestCreateForSelectionAsync(
GetElementRect(sender as FrameworkElement));
}
}
public static Rect GetElementRect(FrameworkElement element)
{
GeneralTransform buttonTransform = element.TransformToVisual(null);
Point point = buttonTransform.TransformPoint(new Point());
return new Rect(point, new Size(element.ActualWidth, element.ActualHeight));
}
上のコードで、スタート画面にセカンダリタイルを作成できるようになった。セカンダリタイルをタップしたときに[画面A]を表示する方法は、次で説明する。
画面遷移の履歴は、Frameコントロール(Windows.UI.Xaml.Controls名前空間)のBackStackプロパティに保持されている。BackStackプロパティは、PageStackEntryオブジェクト(Windows.UI.Xaml.Navigation名前空間)のリストである。従って、PageStackEntryオブジェクトを生成してBackStackプロパティに追加すればよい。
例えば、メイン画面(=「MainPage」クラス)を表示したという履歴をBackStackプロパティの末尾に追加するコードは、次のようになる。
rootFrame.BackStack.Add(new PageStackEntry(typeof(MainPage), null, null));
あとは、上のコードの応用である。前述のコードで作成したセカンダリタイルから起動されたときに[画面A](=「PageA」クラス)を表示するコードは、次のようになる。
protected async override void OnLaunched(LaunchActivatedEventArgs e)
{
#if DEBUG
……省略……
#endif
Frame rootFrame = Window.Current.Content as Frame;
if (rootFrame == null)
{
……省略……
}
// タイルのArgumentsを取り出す
string launchArguments = string.Empty;
if (e != null)
launchArguments = e.Arguments;
// セカンダリタイルがタップされたときはlaunchArgumentsの値が"PageA"になる
if (rootFrame.Content == null)
{
#if WINDOWS_PHONE_APP
……省略……
#endif
if (launchArguments == "PageA")
{
// まだ画面が表示されていないときは、まず画面遷移する
rootFrame.Navigate(typeof(PageA));
// それから画面遷移履歴にメイン画面を追加する(順序が逆だとエラーになる)
rootFrame.BackStack.Add(new PageStackEntry(typeof(MainPage), null, null));
Window.Current.Activate();
return;
}
if (!rootFrame.Navigate(typeof(MainPage), e.Arguments))
{
throw new Exception("Failed to create initial page");
}
// (1)
}
else
{
// すでに画面が表示されているとき
if (launchArguments == "PageA")
{
// 現在の画面が[PageA]ではなかったら、画面遷移させる
if (!(rootFrame.Content is PageA))
{
// すでに戻る先の画面は履歴にあるから、画面遷移させるだけでよい
rootFrame.Navigate(typeof(PageA));
}
}
}
// 現在のウィンドウがアクティブであることを確認します
Window.Current.Activate();
}
画面遷移の履歴を追加するには、履歴を表すPageStackEntryオブジェクトを生成し、それをFrameコントロールのBackStackプロパティに追加すればよい。例として取り上げたセカンダリタイルの場合では、まだ履歴が1つもないときだけ履歴を追加するようにした。
Copyright© Digital Advantage Corp. All Rights Reserved.