×
Namespaces

Variants
Actions
(Difference between revisions)

How to pass a complex object to a page by extending NavigationService on Windows Phone

From Nokia Developer Wiki
Jump to: navigation, search
hamishwillee (Talk | contribs)
m (Hamishwillee - Subedited/Reviewed)
hamishwillee (Talk | contribs)
m (Hamishwillee - - Introduction)
Line 28: Line 28:
 
This is fine if all that is needed is to pass strings, but in some cases it would be useful to be able to pass other (more complex) objects between pages - for example "persons", "employees", "products". Unfortunately as the class is [http://msdn.microsoft.com/en-us/library/vstudio/88c54tsw.aspx sealed], you cannot extend it by inheritance to implement this additional functionality. You can however extend it by implementing a [http://msdn.microsoft.com/en-us/library/vstudio/bb383977.aspx C# extension method].
 
This is fine if all that is needed is to pass strings, but in some cases it would be useful to be able to pass other (more complex) objects between pages - for example "persons", "employees", "products". Unfortunately as the class is [http://msdn.microsoft.com/en-us/library/vstudio/88c54tsw.aspx sealed], you cannot extend it by inheritance to implement this additional functionality. You can however extend it by implementing a [http://msdn.microsoft.com/en-us/library/vstudio/bb383977.aspx C# extension method].
  
This article shows how to provide the required functionality. It provides two implementations: the first for sharing complex objects between any two pages, the second which uses a dictionary for storing the object and a key - making it easier to share objects that might be needed by multiple pages.
+
This article shows how to provide the required functionality. It provides two implementations: the first for sharing complex objects between any two pages, the second which uses a dictionary for storing the object and a key - making it easier to share objects in multi-page hierarchies.
 
+
  
 
== Complex object in a static variable ==
 
== Complex object in a static variable ==

Revision as of 05:42, 26 November 2013

This article explains how to pass a complex object to a Windows Phone page by extending the NavigationService.

SignpostIcon XAML 40.png
WP Metro Icon WP8.png
SignpostIcon WP7 70px.png
Article Metadata
Tested with
SDK: Windows Phone 7.1 SDK, Windows Phone 8.0 SDK
CompatibilityArticle
Created: Kunal Chowdhury (04 Nov 2013)
Last edited: hamishwillee (26 Nov 2013)

Contents

Introduction

NavigationService (in System.Windows.Navigation namespace) provides methods and events to support navigation from one page to another in a Windows Phone app. The Navigate() method takes one parameter of type Uri. You can pass strings between pages by specifying them as a Query String parameter when sending, and then retrieve them in the receiving page using the NavigationContext.

This is fine if all that is needed is to pass strings, but in some cases it would be useful to be able to pass other (more complex) objects between pages - for example "persons", "employees", "products". Unfortunately as the class is sealed, you cannot extend it by inheritance to implement this additional functionality. You can however extend it by implementing a C# extension method.

This article shows how to provide the required functionality. It provides two implementations: the first for sharing complex objects between any two pages, the second which uses a dictionary for storing the object and a key - making it easier to share objects in multi-page hierarchies.

Complex object in a static variable

While we could have a separate static variable in the app for holding values to be passed between pages, it is more elegant to use the NavigationService. While this class cannot be extended by inheritance, we can extend it using an extension method! This allows us to create a method overload which takes an arbitrary object, which we store in a static variable.

The implementation of the Navigate() method is as below:

    public static void Navigate(this NavigationService navigationService, Uri source, object data)
{
Data = data;
navigationService.Navigate(source);
}

The first parameter indicates that this is an extension method of NavigationService class, and should not be specified when the function is used. To use this function specify the target page (URI) and object to pass, respectively. The object passed to the method is stored in a static variable.

Here is a code snippet showing how the extension method is used:

    private void OnNextButtonClicked(object sender, RoutedEventArgs e)
{
var person = new Person {Name = "Kunal Chowdhury", Blog = "www.kunal-chowdhury.com"};
NavigationService.Navigate(new Uri("/NextPage.xaml", UriKind.Relative), person);
}

In the destination page we call another extension method GetNavigationData() to get the passed object (instead of calling NavigationContext to get the query string parameter value):

    protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
 
var person = (Person)NavigationService.GetNavigationData();
MessageBox.Show("Blog of " + person.Name + " is: " + person.Blog);
}


You can keep the data object in NavigationService or you can nullify it once you retrieve it - keeping the data object allows you to easily pass the same object to second page.

Below is the complete source code of the extension methods of the NavigationService:

    public static class Extensions
{
private static object Data;
 
/// <summary>
/// Navigates to the content specified by uniform resource identifier (URI).
/// </summary>
/// <param name="navigationService">The navigation service.</param>
/// <param name="source">The URI of the content to navigate to.</param>
/// <param name="data">The data that you need to pass to the other page
/// specified in URI.</param>
public static void Navigate(this NavigationService navigationService, Uri source, object data)
{
Data = data;
navigationService.Navigate(source);
}
 
/// <summary>
/// Gets the navigation data passed from the previous page.
/// </summary>
/// <param name="service">The service.</param>
/// <returns>System.Object.</returns>
public static object GetNavigationData(this NavigationService service)
{
return Data;
}
}


Multi-page hierarchies - Using a Dictionary to store shared data

Consider the case of navigating into a multi-page hierarchy using the API defined in the previous section. If you navigate to a page using a particular object and then navigate to another page using another object then the first object that was passed is lost - if you go back to the page it will have access to data for the wrong page.

While it is possible to work around this in each page, it is again more elegant to store the appropriate navigation data in the extension method. In this section we store the data in a Dictionary and use a key to get the correct object when needed.

To implement such behaviour in your NavigationService extension, first declare a Dictionary of type <string, object> as shown below:

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

Then implement the Navigate() method to pass Uri, key and data to that method. Make sure that, you are checking the pre-existence of the key in the dictionary.

    public static void Navigate(this NavigationService navigationService, Uri source, string key, object data)
{
if (Data.ContainsKey(key))
{
Data.Remove(key);
}
 
Data.Add(key, data);
navigationService.Navigate(source);
}

Similarly, in the GetNavigationData() method get the value from the dictionary and remove it by default before returning it to the caller method. In some case, you might need to store the data to use in multiple places. This method should handle that properly as shown in the code snippet:

    public static object GetNavigationData(this NavigationContext context, string key, bool persistData = false)
{
var value = Data.ContainsKey(key) ? Data[key] : null;
 
if (persistData == false)
{
context.Remove(key);
}
 
return value;
}

Add some additional methods like Remove() and Clear() in the class to handle the dictionary object properly. Here is the new complete extension methods of the NavigationService class:

    public static class Extensions
{
private static readonly Dictionary<string, object> Data = new Dictionary<string, object>();
 
/// <summary>
/// Navigates to the content specified by uniform resource identifier (URI).
/// </summary>
/// <param name="navigationService">The navigation service.</param>
/// <param name="source">The URI of the content to navigate to.</param>
/// <param name="key">The key.</param>
/// <param name="data">The data that you need to pass to the other page
/// specified in URI.</param>
public static void Navigate(this NavigationService navigationService, Uri source, string key, object data)
{
if (Data.ContainsKey(key))
{
Data.Remove(key);
}
 
Data.Add(key, data);
navigationService.Navigate(source);
}
 
/// <summary>
/// Gets the navigation data passed from the previous page.
/// </summary>
/// <param name="context">The context.</param>
/// <param name="key">The key.</param>
/// <param name="persistData">if set to <c>true</c> [persist data].</param>
/// <returns>System.Object.</returns>
public static object GetNavigationData(this NavigationContext context, string key, bool persistData = false)
{
var value = Data.ContainsKey(key) ? Data[key] : null;
 
if (persistData == false)
{
context.Remove(key);
}
 
return value;
}
 
/// <summary>
/// Removes the specified context.
/// </summary>
/// <param name="context">The context.</param>
/// <param name="key">The key.</param>
public static void Remove(this NavigationContext context, string key)
{
if (Data.ContainsKey(key))
{
Data.Remove(key);
}
}
 
/// <summary>
/// Clears the specified context.
/// </summary>
/// <param name="context">The context.</param>
public static void Clear(this NavigationContext context)
{
Data.Clear();
}
}

Summary

This article has provided two different ways to implement extension methods to pass complex object to the NavigationService and use it in different pages. There may be other methods - please extend this article as needed!.

268 page views in the last 30 days.
×