システムの[戻る]ボタンに対応するには?[Windows 10 UWPアプリ開発]:WinRT/Metro TIPS
UWPアプリにはシステム提供の[戻る]ボタンを表示できる。本稿では、このボタンを表示し、画面遷移を制御する方法を解説する。
powered by Insider.NET
PC用のWindows 10は、システムが[戻る]ボタンを表示するようになった。モバイル用のWindows 10には、Windows Phoneの時代から[戻る]ボタンがある。これらの[戻る]ボタンを、Windows 10のユニバーサルWindowsプラットフォーム用のアプリ(以降、UWPアプリ)ではどのように扱えばよいのだろうか? 本稿ではその方法を解説する。なお、本稿のサンプルは「Windows Store app samples:MetroTips #113」からダウンロードできる。
事前準備
デスクトップ用とモバイル(=Windows 10を搭載したスマートフォン)用のUWPアプリを開発するには、以下の開発環境が必要である。本稿では、無償のVisual Studio Community 2015を使っている。
- SLAT対応のPC*1
- 64bit版*2 Windows 10 Pro*3
- Visual Studio 2015(以降、VS 2015)*4
- Windows SDK for Windows 10*5
*1 SLAT対応ハードウエアは、モバイルエミュレーターの実行に必要だ。ただし未対応でも、ソースコードのビルドと実機でのデバッグは可能である。SLAT対応のチェック方法はMSDNブログの「Windows Phone SDK 8.0 ダウンロードポイント と Second Level Address Translation (SLAT) 対応PCかどうかを判定する方法」を参照。なお、SLAT対応ハードウエアであっても、VM上ではエミュレーターが動作しないことがあるのでご注意願いたい。
*2 Windows 10モバイルエミュレーターを使用しないのであれば、32bit版でもよい。
*3 開発に使うWindows 10は「開発者モード」を有効にしておくこと(「設定アプリ」の[更新とセキュリティ]−[開発者向け]で、[開発者モード]ラジオボタンを選択)。そうしないと、VS 2015のXAMLエディターがエラーになる。また、本稿の内容が適用できるのは、Windowsのライフサイクル管理の上では「Windows 10, released in July 2015」と呼ばれるリリース、またはそれ以降。WinVerコマンドで表示されるバージョンは「10.0 (ビルド 10240)」。UWPアプリ開発におけるデバイスファミリーのバージョン指定としては「10.0.0.0」(Package.appxmanifestファイルのTargetDeviceFamily)である。なお、モバイルエミュレーターを使用しないのであれば、Home版でもよい。
*4 本稿に掲載したコードを試すだけなら、無償のExpressエディションやCommunityエディションで構わない。Visual Studio Express 2015 for Windows 10(製品版)はマイクロソフトのページから無償で入手できる(ページの左側で[Visual Studio 2015]−[Express 2015 for Windows 10]と選ぶ)。Expressエディションはターゲットプラットフォームごとに製品が分かれていて紛らわしいが、UWPアプリの開発には「for Windows 10」を使う(「for Desktop」はWPF/Windowsフォーム/Win32 APIのアプリ開発用)。また、Visual Studio Community 2015(製品版)もマイクロソフトのページから無償で入手できる。なお、英語版がインストールされた場合には、Microsoft Visual Studio 2015 Language Packの日本語版を追加インストールし、[オプション]ダイアログで言語を切り替える。
*5 使用しているVS 2015に含まれていない場合は、Windows SDK for Windows 10のページからダウンロードできる。本稿の内容が適用できるのは、作成したプロジェクトのプロパティに表示されるターゲットバージョンが「10.0; ビルド 10240」またはそれ以降。
システムの[戻る]ボタンとは?
モバイル用のWindows 10は、従来のWindows Phone 7.x/8.xを引き継いで、システムが[戻る]ボタンを提供していることはご存じだろう(次の画像)。
モバイル用Windows 10の[戻る]ボタン(Windows 10エミュレーター)
システムが[戻る]ボタンを備えている(赤丸内)。
この例ではスクリーン上に表示されているが、ハードウエアのボタンとして提供される場合もある。
画面遷移をするアプリは、このボタンが押されたときに前の画面に戻るような実装をする必要がある。
PC用のWindows 10でも、タブレットモードにするとタスクバーに[戻る]ボタンが表示される(次の画像)。
PC用Windows 10のタスクバーに表示される[戻る]ボタン(タブレットモード)
システムがタスクバー上に[戻る]ボタンを備えている(赤丸内)。
画面遷移をするUWPアプリは、このボタンが押されたときに前の画面に戻るような実装をする必要がある。
さらに、PC用のWindows 10では、タイトルバーに[戻る]ボタンが表示されているUWPアプリもある(次の画像)。これは、上の画像にあるタスクバー上の[戻る]ボタンと同じくシステムが表示しているボタンであり、タスクバー上の[戻る]ボタンとほぼ同じ動作をする。
PC用Windows 10のUWPアプリのタイトルバーに表示される[戻る]ボタン
上: タブレットモードでないとき(いわゆる「デスクトップモード」)。
下: タブレットモード時。
システムがタイトルバー(水色の部分)の左端に[戻る]ボタンを表示している(赤丸内)。これは一部のUWPアプリだけに表示される。どうやって表示しているのだろうか?
なお、この2枚の画像だけは、インサイダープレビュー版のWindows 10(ビルド10532)を使っている。タイトルバーに色が付くので分かりやすいからだ。
なお、現在のWindows 10 IoT Coreでは、システムが[戻る]ボタンを提供していないことが分かっている(英語フォーラムのスレッド参照)。PCとモバイル以外のデバイスにも対応するUWPアプリの場合は、デバイスに応じてアプリ独自の[戻る]ボタンを表示する必要が出てくる。
タイトルバーに[戻る]ボタンを表示するには?
UWPアプリのタイトルバーに[戻る]ボタンを表示するには、SystemNavigationManagerオブジェクト(Windows.UI.Core名前空間)のAppViewBackButtonVisibilityプロパティを設定すればよい。このプロパティはユニバーサルなので、デバイスによる切り分けは不要である。ただし、本稿執筆時点ではデスクトップ用Windows 10だけで有効だ(モバイルでは何も起きない)。
例えば、ページのOnNavigatedToメソッドのオーバーライドで、次のコードのように記述する。Windowsランタイムアプリは、「どのページを表示しているか」やページ間の遷移の履歴を、ページ内のFrameコントロール(Windows.UI.Xaml.Controls名前空間)で管理している。そこで、ページ内のFrameコントロールが前の画面に戻れる状態のとき(例えば、MainPage.xamlファイルで定義されている画面からAnotherPage.xamlファイルで定義されている画面に遷移をしたとき)は[戻る]ボタンを表示し、そうでないとき(例えば、アプリ実行直後にMainPage.xamlで定義されている画面が表示されたとき)は非表示にする。
Windows.UI.Core.SystemNavigationManager.GetForCurrentView()
.AppViewBackButtonVisibility
= Frame.CanGoBack
? Windows.UI.Core.AppViewBackButtonVisibility.Visible
: Windows.UI.Core.AppViewBackButtonVisibility.Collapsed;
Windows.UI.Core.SystemNavigationManager.GetForCurrentView() _
.AppViewBackButtonVisibility _
= If(Frame.CanGoBack,
Windows.UI.Core.AppViewBackButtonVisibility.Visible,
Windows.UI.Core.AppViewBackButtonVisibility.Collapsed)
ページのOnNavigatedToメソッドのオーバーライドに、このコードを追加する。
システムの[戻る]ボタンに対応するには?
システムの[戻る]ボタンがタップ/クリックされたときの処理は、SystemNavigationManagerオブジェクトのBackRequestedイベントで行えばよい。このイベントもユニバーサルであり、モバイル用Windows 10でも動作する。
例えば、次のコードのようにして、ページのOnNavigatedToメソッドのオーバーライドでイベントハンドラーを結び付け、イベントハンドラー内で前の画面に戻す処理を行う。
注意点が二つある。一つは、タスクバー上の[戻る]ボタンとモバイルの[戻る]ボタンは常に操作が可能なため、画面遷移履歴のない状態でも[戻る]ボタンが押せることだ。二つ目は、タスクバー上の[戻る]ボタンかモバイルの[戻る]ボタンが押されたときは、イベントハンドラーの引数eのHandledプロパティをtrueにセットする必要があることだ。trueにセットしないと、以前に表示していたアプリ(またはスタート画面)に戻ってしまう(これは、画面遷移履歴のない状態では正常な動作だ)。
protected override async void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
……省略……
// システムの[戻る]ボタンに対応するイベントハンドラーを結び付ける
Windows.UI.Core.SystemNavigationManager.GetForCurrentView()
.BackRequested += MainPage_BackRequested;
}
protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
{
base.OnNavigatingFrom(e);
……省略……
// システムの[戻る]ボタンに対応するイベントハンドラーを解除する
Windows.UI.Core.SystemNavigationManager.GetForCurrentView()
.BackRequested -= MainPage_BackRequested;
}
// システムの[戻る]ボタンが押された時のイベントハンドラー
private void MainPage_BackRequested(object sender,
Windows.UI.Core.BackRequestedEventArgs e)
{
if (Frame.CanGoBack)
{
Frame.GoBack();
e.Handled = true;
}
}
Protected Overrides Async Sub OnNavigatedTo(e As NavigationEventArgs)
MyBase.OnNavigatedTo(e)
……省略……
' システムの[戻る]ボタンに対応するイベントハンドラーを結び付ける
AddHandler _
Windows.UI.Core.SystemNavigationManager.GetForCurrentView().BackRequested,
AddressOf MainPage_BackRequested
End Sub
Protected Overrides Sub OnNavigatingFrom(e As NavigatingCancelEventArgs)
MyBase.OnNavigatingFrom(e)
……省略……
' システムの[戻る]ボタンに対応するイベントハンドラーを解除する
RemoveHandler _
Windows.UI.Core.SystemNavigationManager.GetForCurrentView().BackRequested,
AddressOf MainPage_BackRequested
End Sub
' システムの[戻る]ボタンが押された時のイベントハンドラー
Private Sub MainPage_BackRequested(sender As Object,
e As Windows.UI.Core.BackRequestedEventArgs)
If (Frame.CanGoBack) Then
Frame.GoBack()
e.Handled = True
End IfEnd Sub
システムの[戻る]ボタンは常に操作可能なので、イベントハンドラー内では前の画面に遷移できることを必ず確認する。また、画面遷移できた場合は、「e.Handled」をtrueに設定して、画面遷移したことをシステムに通知する。
ハンバーガーメニューを使った画面遷移の場合は?
さて、トップレベルのFrameコントロール内で画面遷移を行っている場合は、以上のようにそれぞれのページの中で[戻る]ボタンの処理を行えばよいのだが、メインページの中にナビゲーションメニューとそのコンテンツとしてFrameコントロールを置き、そのFrameコントロール内で画面を遷移させている場合はどうだろう? 「WinRT/Metro TIPS:ハンバーガーメニューで画面を遷移させるには?[Windows 10 UWPアプリ開発]」で紹介したような場合だ。
Frameコントロールは、外部からでもGoBackメソッドを呼び出してその内容だけを前のページに戻せる。つまり画面遷移については上記のようなコンテンツ構成でも問題なく実装できる。ただし、Frameコントロールの内容を前のページに戻したときに、ナビゲーションメニューの方でも同期を取ってアクティブになっている状態を変えなければならない(コンテンツとして配置したFrameコントロールにどのページが表示されているかがメニューに反映されるようにする)。ここが少々工夫の必要になるところだ。それには、FrameコントロールのNavigatedイベントを使うとよい。
例えば次の図のように、「MainPage」クラスに二つのイベントハンドラーを追加する。一つは前述したBackRequestedイベントのハンドラーだが、そこで呼び出すGoBackメソッドをコンテンツのFrameコントロールのものとする点が異なる。二つ目は、コンテンツのFrameコントロールのNavigatedイベントを受けるハンドラーだ。このハンドラーはFrameコントロール内での画面遷移が完了したときに呼び出されるので、ここでナビゲーションメニュー(図の中では「ハンバーガーメニュー」)の同期を取ればよい。具体的なコードは、別途公開のサンプルコードをご覧いただきたい。
ハンバーガーメニューを使った画面遷移の場合
システムの[戻る]ボタンがタップ/クリックされると、SystemNavigationManagerオブジェクトのBackRequestedイベントが発生するので、それを受けるイベントハンドラー内でFrameコントロールのGoBackメソッドを呼び出す。
Frameコントロール内で画面遷移が完了するとNavigatedイベントが発生するので、それを受けるイベントハンドラー内でハンバーガーメニューの同期を取る。このハンバーガーメニューはラジオボタンを使って実装しているため、同期を取るコードが少々面倒になる。ラジオボタンの選択状態をいったん全てOFFにしないと、目的のボタンをONにできないからだ。具体的なコードは、別途公開のサンプルコードを見てほしい。
このようにすることで、[戻る]ボタンへの対応も含めて画面遷移のコードビハインドは全て「MainPage」クラスに集約される。コンテンツの各ページ(「Page1.xaml」「Page2.xaml」「Page3.xaml」)の中では、画面遷移のことを全く考慮せずに済むのである。
実行している様子を次の画像に示す。
完成したハンバーガーメニューを使った画面遷移の例
上: ハンバーガーメニューを使って、[ページ【1】]→[ページ【2】]→[ページ【3】]と画面遷移したところ。一番下のメニューが選択状態になっている(赤矢印)。ここでシステムの[戻る]ボタン(赤丸内)をタップ/クリックする。
下: すると、前の画面[ページ【2】]に戻るとともに、メニューの選択状態も下から二番目に変わる(赤矢印)。
なお、ハンバーガーメニュー下端の[About]項目と、モバイルの画面上端に表示されているタイトルバーのようなものについては、本稿では解説していない。別途公開のサンプルをご覧いただきたい。
まとめ
システムの[戻る]ボタンがタップ/クリックされたときの処理は、SystemNavigationManagerオブジェクトのBackRequestedイベントでユニバーサルに行える。ただし、デバイスによってはシステムが[戻る]ボタンを提供していないこともあるので注意が必要だ(本稿執筆時点ではIoT Coreにはないことが分かっている)。
なお、Frameコントロールには画面遷移が完了したときに発生するイベントがある。画面内にFrameコントロールを配置するときは思い出してほしい。
Copyright© Digital Advantage Corp. All Rights Reserved.