43

On the windows phone 7 emulator, when the hardware back button is pressed, the default behaviour is for it to close your current application. I want to override this default behaviour so that it navigates to the previous page in my application.

After some research, it seems it should be possible to do this by overriding the OnBackKeyPress method, like so:

protected override void OnBackKeyPress(System.ComponentModel.CancelEventArgs e)
{
    // do some stuff ...

    // cancel the navigation
    e.Cancel = true;
}

However, clicking the back button still closes my application. Putting a breakpoint on the above method reveals that it is never called. I have another breakpoint on my application exit code, and this breakpoint is hit.

Is there something else I need to do to intercept the back button?

skaffman
  • 398,947
  • 96
  • 818
  • 769
David_001
  • 5,703
  • 4
  • 29
  • 55
  • 2
    Overriding the OnBackKeyPress() from my MainPage.xaml and calling e.Cancel worked fine for me. – BrokeMyLegBiking Dec 20 '10 at 04:13
  • you can handle the back button , [check this post answer of me][1] [1]: http://stackoverflow.com/questions/8975822/prompt-confirmation-dialog-when-exit-app/8977078#8977078 – Santhu Jan 27 '12 at 10:46

3 Answers3

29

It would appear that it's not possible to override the OnBackKeyPress method to intercept the back key unless you use the Navigate method to move between pages in your application.

My previous method of navigation was to change the root visual, like:

App.Current.RootVisual = new MyPage(); 

This meant I could keep all my pages in memory so I didn't need to cache the data stored on them (some of the data is collected over the net).

Now it seems I need to actually use the Navigate method on the page frame, which creates a new instance of the page I'm navigating to.

(App.Current.RootVisual as PhoneApplicationFrame).Navigate(
                                    new Uri("/MyPage.xaml", UriKind.Relative)); 

Once I started navigating using this method, I could then override the back button handling in the way described in my question...

David_001
  • 5,703
  • 4
  • 29
  • 55
  • Indeed if you use navigate then override the back button then you can implement a new behaviour for it (checked this myself!). – RoguePlanetoid May 20 '10 at 18:34
  • Is there *any* other way to do it? What if all the interactions are being done on one page? Is it then impossible to override the back button? – Hosam Aly Dec 13 '10 at 13:35
  • I would suggest having a "dummy"-page that navigates to your main page when the application starts, that way you could override the back button in your main page. – Pking Feb 14 '13 at 11:23
23

If you don't want the default back key behavior, set Cancel = true in the CancelEventArgs parameter in OnBackKeyPress. In my page, I've overridden the back button to close a web browser control instead of navigating back.

    protected override void OnBackKeyPress(CancelEventArgs e)
    {
        if (Browser.Visibility == Visibility.Visible)
        {
            Browser.Visibility = Visibility.Collapsed;
            e.Cancel = true;
        }
    }
ManicBlowfish
  • 2,258
  • 2
  • 21
  • 29
3

I was able to use this technique to do what I wanted, which is to prevent back navigation while hiding a control that slides in and out of the window. By default, the control's visibility is collapsed. Storyboards are used to control when it becomes visible or collapsed. In XAML, inside the Storyboard:

<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ControlScroller" Storyboard.TargetProperty="(UIElement.Visibility)">
<ObjectAnimationUsingKeyFrames.KeyFrames>
    <DiscreteObjectKeyFrame KeyTime="00:00:00">
        <DiscreteObjectKeyFrame.Value>
            <Visibility>Visible</Visibility>
        </DiscreteObjectKeyFrame.Value>
    </DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames.KeyFrames>

Then in the page's code:

protected override void OnBackKeyPress(System.ComponentModel.CancelEventArgs e)
{

    if(ControlScroller.Visibility == Visibility.Visible  && StoryboardHideControlSlider.GetCurrentState() != ClockState.Active)
    {
        StoryboardHideControlSlider.Begin();

        ContentGrid.IsHitTestVisible = true;

        e.Cancel = true;
    }
}

Note: In the Storyboard that hides the ContentScroller (which is a grid), the KeyTime is set to "00:00:01" because I want it to remain visible while it is sliding (and fading) out of view.

Note 2: The reason StoryboardHideControlSlider.GetCurrentState() != ClockState.Active is included in the if statement is because if the user hits the back button twice and the Storyboard hasn't completed it will run again. This prevents the backbutton cancelling navigation back to the previous page. So in other words, if the Storyboard is active, the code "knows" that the user has already initiated hiding it and intends to navigate back to the previous page. (Well, at least that's behavior they're going to get...and they won't see the animation twice)!

Stonetip
  • 1,150
  • 10
  • 20