kazuakix の日記

Windows Phone とか好きです

Windows Phone 8.1 で戻るボタンを制御する

戻るボタンで前の画面に戻りたくないとき、 Windows Phone 8 までは OnBackKeyPress をオーバーライドして e.Cancel = true としていました。

protected override void OnBackKeyPress(System.ComponentModel.CancelEventArgs e)
{
    if (何かしらの条件)
    {
        e.Cancel = true;  // 戻らない
    }
    base.OnBackKeyPress(e);
}

 
Silverlight アプリであれば Windows Phone 8.1 でも同じなのですが、WinRT で作ろうとすると OnBackKeyPress はありません。代わりに HardwareButton クラスの BackPressed イベントの中で e.Handled = true とすることで対応します。Page クラスでない事からもなんとなく想像つくようにページごとではなくアプリで共通になります。
 
ちなみにこの辺の処理について書かれているドキュメントはこちら

上記ページには 「次のコードが App.xaml.cs ファイルに用意されています。」とありますが、残念ながら見当たりません。代わりに基本ページを作ったときに自動的に追加される超絶便利な NavigationHelper クラスに以下のコードが埋め込まれていました。

public NavigationHelper(Page page)
{
    this.Page = page;

    // このページがビジュアル ツリーの一部である場合、次の 2 つの変更を行います:
    // 1) アプリケーションのビューステートをページの表示状態にマップする
    // 2) ハードウェアのナビゲーション要求を処理する
    this.Page.Loaded += (sender, e) =>
    {
#if WINDOWS_PHONE_APP
        Windows.Phone.UI.Input.HardwareButtons.BackPressed += HardwareButtons_BackPressed;
#else
        // 省略
#endif
    };

    // ページが表示されない場合、同じ変更を元に戻します
    this.Page.Unloaded += (sender, e) =>
    {
#if WINDOWS_PHONE_APP
        Windows.Phone.UI.Input.HardwareButtons.BackPressed -= HardwareButtons_BackPressed;
#else
        // 省略
#endif
    };
}

private void HardwareButtons_BackPressed(object sender, Windows.Phone.UI.Input.BackPressedEventArgs e)
{
    if (this.GoBackCommand.CanExecute(null))
    {
        e.Handled = true;
        this.GoBackCommand.Execute(null);
    }
}


NavigationHelper クラスを使うページごとに BackPressed イベントを登録しているのですが、その処理は共通のようですね。特定のページでだけ戻るボタンを制御したい場合、例えば共通の中で場合分けをしてやる方法があります。

private void HardwareButtons_BackPressed(object sender, Windows.Phone.UI.Input.BackPressedEventArgs e)
{
    var frame = Window.Current.Content as Frame;
    if (frame.Content.GetType().Equals(typeof(BasicPage1)))
    {
        if (何かしらの条件)
        {
            e.Handled = true;
            return;
        }
    }

    if (this.GoBackCommand.CanExecute(null))
    {
        e.Handled = true;
        this.GoBackCommand.Execute(null);
    }
}

 
もしくは BackPressed イベントを NavigationHelper クラスで登録・解除せずに、全ページに自分で書いていく等でしょうか? どういった方法がいいのか悩ましいですね。