コードによるナビゲーション
これまではHyperlinkButtonコントロールによるナビゲーションを紹介してきましたが、アプリケーションコードからナビゲーションを行うことももちろん可能です。
フレームのSourceプロパティーを切り替える
リスト8はMainPage.xamlに配置されたFrameコントロールを利用してページを移動する方法です。
private void Button_Click(object sender, RoutedEventArgs e)
{
var button = sender as Button;
if (button == null) return;
ContentsFrame.Navigate(new Uri("/" + button.Tag), UriKind.Relative);
// FrameコントロールのSourceプロパティーに設定してもOK
// ContentsFrame.Source = new Uri("/" + button.Tag), UriKind.Relative);
}
この例ではクリックされたボタンのTagプロパティーに設定された文字列をもとにページを移動しています。たとえば、次のようにボタンが定義されている場合、ボタンをクリックすると/Views/AboutPage.xamlに移動します。
<Button Content="概要" Click="Button_Click" Tag="About" />
ページのNavigationServiceで移動する
ナビゲーションフレームワークのPageクラスを継承するページでは、NavigationServiceプロパティーを利用することでページの切り替えが可能です。また移動履歴を元に「前へ移動」や「後ろへ移動」といった移動も可能です。
リスト9のように「次へ」「後へ」「トップ」へと、それぞれに移動するためのボタンが定義されているとします。
<Button x:Name="NavigateForward" Content="次へ" Click="GoForward_Click" /> <Button x:Name="NavigateBack" Content="前へ" Click="GoBack_Click" /> <Button x:Name="NavigateTop" Content="トップへ" Click="GoTop_Click" />
履歴情報を基に移動する場合、履歴がない場合にInvalidOperationExceptionの例外が発生する可能性があります。リスト10ではページに移動した時に、履歴情報が存在するかを調べ、存在しない場合はボタンをクリックできないように変更し、存在するボタンのイベントハンドラーで移動を行っています。
// ユーザーがこのページに移動したときに実行されます。
protected override void OnNavigatedTo(NavigationEventArgs e)
{
NavigateForward.IsEnabled = NavigationService.CanGoForward;
NavigateBack.IsEnabled = NavigationService.CanGoBack;
}
/// <summary>次のページへ移動</summary>
private void GoForward_Click(object sender, RoutedEventArgs e)
{
NavigationService.GoForward();
}
/// <summary>前のページへ移動</summary>
private void GoBack_Click(object sender, RoutedEventArgs e)
{
NavigationService.GoBack();
}
/// <summary>Topページへ移動</summary>
private void GoTop_Click(object sender, RoutedEventArgs e)
{
NavigationService.Navigate(new Uri("/Top", UriKind.Relative));
}
各ページでNavigationServiceプロパティーを利用してナビゲーションする場合、UriMapperは親のフレームが持っている物が自動的に適用されるようです。
ページの移動に失敗した場合にエラーメッセージを表示する
ページの移動が終了した場合やページの移動に失敗した場合は、ページやフレームにあらかじめ定義されているイベントを処理することでハンドリングが可能になっています。リスト11ではページ移動時にエラーが発生した場合にエラーメッセージを表示する例です。
public MainPage()
{
InitializeComponent();
ContentsFrame.NavigationFailed += (source, e) =>
{
MessageBox.Show(string.Format(
"{0}へのページ移動時にエラーが発生しました。\n{1}", e.ToString()));
};
}
まとめ
どうでしょう、最初にあげた2種類の方法よりも簡単に分かりやすい方法で画面遷移が行えるようになったことを少しでも実感できたでしょうか。
ただ、一つのXAPファイルにあまりにもたくさんのページを内包するような構成の場合、アプリケーションのサイズもかなり大きくなってしまいます。このためナビゲーションフレームワークを利用する場合は、サブシステムの分割やサブシステム間の連携などを考慮に入れ設計する必要があります。また、ナビゲーションフレームワークを利用せずに、最初にあげた例のようにHTML-DOM連携を使ってページを移動する方法も場合によっては利用できるでしょう。
このあたりはまだ筆者も、この時はこうしたらいいといったベストプラクティスを持っていません。とはいえ、ページやアセンブリ、XAPを動的にロードして利用するといったシナリオも思いつきます。このあたりは筆者のブログなどで今後取り上げていきますのでこちらも時間のあるときに確認してみてください。
