2

I am currently trying to implement a navigation scheme that closely resembles that of the Internet Explorer app on Windows Phone 8.

The IE app can have multiple tabs that the user can switch between. Each of these tabs has its own history. Hitting the Back Button on the phone takes you to the previous page in that tab's Navigation history (Not the PhoneApplicationFrame.BackStack). If there are no previous pages, the back button takes you to the previous opened tab or, if none, exits the app.

Why this is troubling me

  • Application.RootVisual can only be set once. So you can't have two PhoneApplicationFrames, each with its own BackStack, to swap RootVisual between the two.

  • You cannot traverse the BackStack (it is a Stack, after all). Can only call GoBack(). Calling GoForward() will throw an Exception.

  • PhoneApplicationFrame.GoBack() removes entries from the BackStack which can only be added again through the PhoneApplicationFrame.Navigate(...) method. So, manipulating the BackStack is a no-go.

Bright Ideas

  • Keep a Dictionary<enum, List<string>> which is updated with each call to a custom NavigationService.Navigate(tabTypeEnum, uriString, params). This will keep the Navigation history for each tabType, allowing us to possibly Navigate through the current Tab's history when the BackKeyPress event is handled. Bad thing is, calling Navigate(...) to go to previous pages (instead of GoBack) will add to the BackStack. So requires maintenance that hurts my brain right now.

  • Create a custom NavigationAwareTabPage : PhoneApplicationPage, which keeps track of its own navigation history and fakes navigation by animating a transition when its Content is changed. The only time we call a true Navigate is when we switch from one tab to another. (I think this is what the IE app does.) And the BackKeyPress would have to look like below.

This:

void RootFrame_BackKeyPress(object sender, CancelEventArgs e)
{
    var rootFrame = sender as PhoneApplicationFrame;
    if (rootFrame.CanGoBack)
    {
        // Get the NavigationAwarePage
        var navAwarePage = rootFrame.Content as NavigationAwareTabPage;
        if(navAwarePage.CanGoBack())
        {
            // This method "navigates" to the next page
            // by changing the navAwarePage.Content
            navAwarePage.GoBackToPreviousPage();
            e.Cancel = true;
        }
    }
}

Has anyone been down this road?

Community
  • 1
  • 1
Chris Leyva
  • 3,478
  • 1
  • 26
  • 47

1 Answers1

1

All the magic of how ReactiveUI overrides the Back button is here:

https://github.com/reactiveui/ReactiveUI/blob/master/ReactiveUI.Mobile/WP8AutoSuspendApplication.cs#L91

The way that this works in ReactiveUI is that there is a content control named RoutedViewHost that is listening to the Back being signaled (you can do whatever you want in response to the hardware Back button and cancel the default action). ReactiveUI maintains its own ViewModel-based back stack and manipulates that instead of using WP8s, and you never call WP8s navigation methods.

This effectively means that, from WP8's perspective, there is only ever one page in the entire application. WP8 really wants to create that page itself, and it's specified in WMAppManifest.xml.

Don't try to participate in WP8's Frame system, it really wants to work its own way and you won't be able to convince it otherwise.

One last important thing, if you're at the bottom of your back stack, you must allow the default Back action to happen (i.e. what WP8 wanted to do, take you out of the app). Otherwise you'll probably fail Certification and you're Doing It Wrong™.

Ana Betts
  • 73,868
  • 16
  • 141
  • 209
  • Thank you very much. I was going to mention the Certification requirement but you beat me to it! Thank you so much. I think this is exactly what I was looking for. – Chris Leyva Nov 20 '13 at 20:06