I received an interesting question from a customer today. He wanted to know how to manipulate the navigation history to skip a page in the backstack in a Windows Store app. In other words, he wanted to do in Windows 8 something similar to what NavigationService.RemoveBackEntry does in Windows Phone 7.1. The scenario he presented was one in which the navigation flow includes a login page, but once the user has logged in and navigated to another page, clicking the back button should take the user to the page that preceded the login page rather than back to the login page itself.

Believe it or not, this isn’t a scenario that WinRT supports. However, where there’s a will, there’s a way. For Process Lifetime Management (PLM) purposes, the Frame class used in XAML apps contains methods named GetNavigationState and SetNavigationState that let you save and restore the app’s current navigation state. GetNavigationState returns a string that represents the serialized navigation state, which includes all the pages in the backstack, the parameters they were passed, and the order in which they were visited. SetNavigationState accepts a string and restores the backstack to the state represented therein. It also navigates to the page marked in the backstack as the current page, although that fact doesn’t appear to be documented. It’s significant, however, because it means you can’t manipulate the backstack without incurring a navigation, too.

The format of serialized navigation strings isn’t documented, but it’s relatively easy to reverse-engineer. (In some of the pre-RTM SDKs, the format was documented. But the RTM docs simply say that “serialization format used by these methods is for internal use only.”) And once you’ve done the reverse engineering, it’s not hard to manipulate the navigation state by adding and removing entries.

To demonstrate, I wrote an extension method named GoBack2 for the Frame class. Patterned after the GoBack method, which navigates to the previous page in the backstack, GoBack2 navigates to the page before the previous page in the backstack and removes the entry representing the previous page so a call to GoForward won’t accidentally land the user on that page. It’s just one example of how to manipulate the navigation state, but one that specifically solves the problem of removing login pages and other one-time pages from the backstack following a successful navigation.

Here’s the source code for the extension method:

public static class WindowsStoreExtensions
{
    public static void GoBack2(this Frame frame)
    {
        var parts = frame.GetNavigationState().Split(',');
        var count = Int32.Parse(parts[1]);

        if (count > 2)
        {
            int index1 = 3;

            // Find the beginning of the next-to-last entry
            for (int i = 0; i < count - 2; i++)
                index1 = FindNextEntry(parts, index1);

            // Find the beginning of the last entry
            int index2 = FindNextEntry(parts, index1);

            // Subtract 1 from the page count and 2 from the page index
            parts[1] = (Int32.Parse(parts[1]) - 1).ToString();
            parts[2] = (Int32.Parse(parts[2]) - 2).ToString();

            // Stringify the results and navigate back two pages by calling SetNavigationState
            var state = String.Join(",", parts, 0, index1) + "," + String.Join(",", parts, index2, parts.Length - index2);
            frame.SetNavigationState(state);
        }
    }

    private static int FindNextEntry(string[] entries, int index)
    {
        if (entries[index + 2] == "0")
            return index + 3;
        else if (entries[index + 3] == "0")
            return index + 4;
        else
            return index + 5;
    }
}

Once this code is added to your project, you can call GoBack2 rather than GoBack when the back button is clicked to skip the previous page in the backstack:

private void OnBackButtonClicked(object sender, RoutedEventArgs e)
{
    this.Frame.GoBack2();
}

Keep in mind that this code may break in a future version of Windows since the serialization format for navigation state could change. Also remember that from a UX standpoint, it’s usually preferable to present a login UI by presenting it in the settings pane than by navigating the user to a dedicated login page. Nevertheless, you might encounter scenarios in which it’s desirable – even necessary – to manipulate the navigation history. If you do, you’ll now have something to go on.