Silverlight 3 Quick Tip #6: Navigation Framework and Uri Routing
Silverlight 3 introduced the Navigation Framework and URI Routing features. Today I’ll show how to use those features.
To use navigation features you could either create a new “Silverlight Navigation Application” or simply add relevant references to standard “Silverlight application”

In case of standard “Silverlight Application” you need to add reference to “System.Windows.Controls.Navigation” assembly and relevant XAML introduce namespace:
xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
To use the navigation feature, simply add new Frame to your XAML page. Frame could have default content, specify Journal usage (own history storage or integration within browser’s history), raise navigation related events.
<navigation:Frame x:Name="frame" Source="/Pages/DefaultPage.xaml"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
Padding="15,10,15,10"
Margin="5,0"
Background="White">
<TextBlock Text="This is default content for the navigation frame" FontFamily="Times New Roman" FontSize="25"/>
</navigation:Frame>
To navigate to new page use “Navigate” function of Frame object:
frame.Navigate(new Uri(“/Pages/Page1.xaml”, UriKind.Relative));
Navigation could be done to class instances derived from “System.Windows.Controls.Page” class. The simplest way to create such a class (and XAML) is by adding to the project new item from “Silverlight Page” type:
In addition to navigation, the Frame provides functionality to navigate Forward/Backward according to own/browsing history. Sample “Next”/“Previous” button handlers:
private void btnNext_Click(object sender, RoutedEventArgs e)
{
if (frame.CanGoForward)
frame.GoForward();
}
private void btnPrev_Click(object sender, RoutedEventArgs e)
{
if (frame.CanGoBack)
frame.GoBack();
}
The history definition for the frame defined by JournalOwnership dependency property:
| Automatic [default] |
Whether or not this Frame will create and use its own journal depends on its parent |
| OwnsJournal |
The Frame maintains its own journal |
| UsesParentJournal |
The Frame uses the journal of the next available navigation host up the content tree, if available. Otherwise, navigation history is not maintained for the Frame |
To raise navigation related events subscribe to themNext:
//This event will be fired when frame is already navigated
this.frame.Navigated += new NavigatedEventHandler(frame_Navigated);
//This event will be fired when frame is navigating
this.frame.Navigating += new NavigatingCancelEventHandler(frame_Navigating);
//This event will be fired when navigation error occurs
this.frame.NavigationFailed += new NavigationFailedEventHandler(frame_NavigationFailed);
By using this Navigation Framework features you could implement deep linking support by URI Routing feature. To use this feature you need to create the UriMapper in application resources. To do so first you need to introduce a namespace in your App.XAML:
xmlns:navcore="clr-namespace:System.Windows.Navigation;assembly=System.Windows.Controls.Navigation"
Then create the UriMapper as a part of application resources:
<Application.Resources>
<navcore:UriMapper x:Key="uriMapper">
<navcore:UriMapping Uri="Home" MappedUri="/Pages/DefaultPage.xaml"/>
<navcore:UriMapping Uri="Link{number}" MappedUri="/Pages/Page{number}.xaml"/>
<navcore:UriMapping Uri="Page/{number}" MappedUri="/Pages/Page{number}.xaml"/>
<navcore:UriMapping Uri="Customers/{id}" MappedUri="/Pages/Page1.xaml?action=getCustomer&id={id}"/>
<navcore:UriMapping Uri="Products/{id}" MappedUri="/Pages/Page1.xaml?action=getProduct&id={id}"/>
<navcore:UriMapping Uri="Stories/{id}&{number}" MappedUri="/Pages/Page1.xaml?action={id}&page={number}"/>
</navcore:UriMapper>
</Application.Resources>
In Beta 1 build the Uri Mapper must have “uriMapper” name, otherwise it will not work.
In my case the mapping is very straightforward:
| Uri |
Target + Description |
| Home |
/Pages/DefaultPage.xaml |
| Link{number} |
/Pages/Page{number}.xaml –-> use {number} as variable received from navigation input |
| Page/{number} |
/Pages/Page{number}.xaml –-> use {number} as variable received from navigation input |
| Customers/{id} |
/Pages/Page1.xaml?action=getCustomer&id={id} –-> use {id} as part of Query String |
| Products/{id} |
/Pages/Page1.xaml?action=getProduct&id={id} –-> use {id} as part of Query String |
| Stories/{id}&{number} |
/Pages/Page1.xaml?action={id}&page={number} –> use {id} and {number} in Query String. You could introduce as many, as you need. |
When navigating, the navigating URI becomes something much more readable (and SEO):
The passed query string parameters could be used on specific page from NavigationContext. While creating new “Silverlight Page” visual studio also creates override function “OnNavigatedTo” which being executed right after navigation to the page:
// Executes when the user navigates to this page.
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (this.NavigationContext.QueryString.ContainsKey("action"))
{
switch (this.NavigationContext.QueryString["action"])
{
case "getCustomer":
txtOutput.Text = "This is DUMMY info CustomerID = " + this.NavigationContext.QueryString["id"];
break;
case "getProduct":
txtOutput.Text = "This is DUMMY info ProductID = " + this.NavigationContext.QueryString["id"];
break;
default:
txtOutput.Text = "This is DUMMY story saved in my sources with ID = "
+ this.NavigationContext.QueryString["action"] + " opened on page #"
+ this.NavigationContext.QueryString["page"];
break;
}
}
}
That’s it for today.
Sample application sources is here.
Enjoy,
Alex