Easy Windows-Phone 7 Navigation

Page navigation in WP7 is crappy:

  1. You must pass an instance of System.Uri which must be of UriKind.Relative
  2. You cannot pass any object but only strings. If you need to pass some object, you usually pass an id and find the object in the target page by the id, assuming you have access to the model, which is usually a public property of some static class.

Here is a sample navigation:

In the source page:

private void NavigateToSomePage()
{
    NavigationService.Navigate(
        new Uri("/SomePage.xaml?data_id=" + data.ID, UriKind.Relative));
}

In the target page:

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    base.OnNavigatedTo(e);

    var data =
        GetTheDataByTheID(NavigationContext.QueryString["data_id"]);

    // continue
}

A kick-ass solution for kick-ass coders

First, a sample navigation using the solution:

In the source page:

private void NavigateToSomePage()
{
    NavigationService.Navigate<SomePage>(data);
}

In the target page:

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    base.OnNavigatedTo(e);

    var data = NavigationContext.GetData<TheDataClass>();

    // continue
}

As you can see, from the source page – we pass only the page name and some data object – of any type.

In-addition, we can use some other overloads:

private void NavigateToSomePage()
{
    NavigationService.Navigate("/SomePage.xaml", data);
}

Or:

private void NavigateToSomePage()
{
    NavigationService.Navigate(typeof(SomePage), data);
}

The strong-named examples work only if the page type name matches the containing xaml file, and the xaml file is at the root.

If the page is not at the root, here is another overload to support such scenario:

private void NavigateToSomePage()
{
    NavigationService.Navigate<SomePage>("Pages", data);
}

The page should be under the “Pages” folder.

The same overload exists also for the non-generic method.

How?

Here is what we need:

  • A dictionary
  • A guid
  • Two extension methods with some overloads
  • A const
public static class Navigator
{
    private const string TheKey = "__data__key__";

    private static readonly Dictionary<string, object> theDict =
        new Dictionary<string, object>();

    public static void Navigate(
        this NavigationService navigationService,
        string pageName,
        object data)
    {
        var guid = Guid.NewGuid().ToString();

        if (data != null)
        {
            theDict.Add(guid, data);
        }

        navigationService.Navigate(
            new Uri(
                string.Format("{0}?{1}={2}",
                    pageName,
                    TheKey,
                    guid),
                UriKind.Relative));
    }

    public static object GetData(this NavigationContext context)
    {
        var guid = context.QueryString[TheKey];

        object data = null;

        if (theDict.TryGetValue(guid, out data))
        {
            theDict.Remove(guid);
        }

        return data;
    }
}

The idea is very simple:

We create a unique key for the specified object, put it in a dictionary, create a uri with that key and from the target page, we use the NavigationContext property to extract the guid from the context and find the object in the dictionary. After we take the object – we remove it from the dictionary so we won’t have an unnecessary reference to it.

Here are some additional overloads:

public static T GetData<T>(this NavigationContext context)
{
    return (T)GetData(context);
}

public static void Navigate<T>(
    this NavigationService navigationService)
    where T : PhoneApplicationPage
{
    Navigate(navigationService, typeof(T), null);
}

public static void Navigate<T>(
    this NavigationService navigationService,
    object data)
    where T : PhoneApplicationPage
{
    Navigate(navigationService, typeof(T), data);
}

public static void Navigate<T>(
    this NavigationService navigationService,
    string path,
    object data)
    where T : PhoneApplicationPage
{
    Navigate(navigationService, path, typeof(T), data);
}

public static void Navigate(
    this NavigationService navigationService,
    Type pageType)
{
    Navigate(
        navigationService,
        string.Format("/{0}.xaml", pageType.Name), null);
}

public static void Navigate(
    this NavigationService navigationService,
    Type pageType,
    object data)
{
    Navigate(
        navigationService,
        string.Format("/{0}.xaml", pageType.Name), data);
}

public static void Navigate(
    this NavigationService navigationService,
    string path,
    Type pageType,
    object data)
{
    Navigate(
        navigationService,
        string.Format("/{0}/{1}.xaml", path, pageType.Name),
        data);
}

Share, please:
  • Digg
  • del.icio.us
  • Google Bookmarks
  • DotNetKicks
  • DZone
  • StumbleUpon
  • Facebook
  • Tumblr
  • Twitter
This entry was posted in .NET, WP7 and tagged , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Spam protection by WP Captcha-Free