This article is compatible with the latest version of Silverlight.
Introduction
With Silverlight 3 a lot of new goodies were introduced and one of them was the navigation framework. It allows us to easily implement navigation between the newly introduced Page controls in a Silverlight application, interacts with the Browser History journal and provides us with Uri mapping. To learn more about these features read on the article.
For this article the demo will be the Mini SilverlightShow application, which I used not a long time ago as a demo to my article about the Telerik's RadPageNavigation control. It is now recreated using the Silverlight Navigation Framework and is known under the codename "Mini Silverlight3Show". :)
Live demo | Source code
Silverlight Navigation Application template
When you try to create new project, you'll notice that there is a new template in the Silverlight section - the Silverlight Navigation Application. This template contains a sample application that has some controls included and some basic UI. You'll notice that it has a folder named "Views" that contains the pages of the application and the MainPage.xaml is used as master page.
You can easily adjust it to a base for your own application or you can of course start from the scratch (there is nothing special in the template that will cause you problems if you choose to start from the Silverlight Application template).
Frame and Page controls
Let's first start with the two controls that the framework introduces to us.
Frame
The Frame is the control that will handle the validation and is the container for the Page control.
Here are some properties and methods that may be considered as most important:
- Source - this property provides the Uri of the page that will be opened in the frame, when the frame is loaded. For example if we have a Home.xaml page in the Views folder (don't forget the "/" at the beginning):
<navigation:Frame x:Name="MainContent" Source="/Views/Home.xaml" />
- Navigate( Uri uri ) - with this method we can navigate through the pages, just pass the correct uri and don't forget the "/" and the Uri Kind:
this.MainContent.Navigate( new Uri( "/Views/Home.xaml", UriKind.Relative ) );
- JournalOwnership - this property determines if the Frame should use its own journal or the one of the browser to store the navigation history. We'll take a look at it a little bit later.
There are also a lot of useful events that may come in handy: Navigating, Navigated, NavigationFailed, NavigationStopped. Also the frame has its own history journal and you are able to navigate through it using the GoBack() and the GoForward() methods. Later we'll talk about the Browser History journal and the Frame control.
Page
The page is not much different than the UserControl, except that it can be loaded in the Frame control. The most interesting here is the Title property, which sets the title of the page in the browser:
<navigation:Page x:Class="MiniSilverlight3Show.Views.Home"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
Title="Mini Silverlight3Show - Home">
Cool, isn't it?
Also we are going to take a closer look to the NavigationService and the NavigationContext properties. The NavigationService allows us to get access to the Frame control that has navigated to this page and via the NavigationContext we can get information about the query string.
Browser History integration
By default the Frame control integrates with the Browser History journal, which means that every page, that the Frame control navigates to, is recorded in that journal:
Now it's time to take look at the JournalOwnership property of the Frame control. It has three values:
- Automatic - If the browser allows, the navigation history will be recorded in its journal, if not - it will be recorded only in the journal of the Frame control.
- OwnsJournal - the Frame control will store the navigation history only in its own history journal.
- UsesParentJournal - the Frame will use the journal of the parent Frame control and the JournalOwnership settings of the parent control are then applied. If there is no parent Frame control, the Browser History journal is used.
If you don't want your Frame to integrate with the browser, to use the built-in history journal and to implement your own logic around the go-back and go-forward actions, this property allows you to do so.
NavigationService and NavigationContext
Let's take a look at the following case: We have navigated to the News page and the latest news has loaded. We want to click on news and to navigate to a page that will display its content. The specific here is that we want to place navigation logic into a page that is loaded in the Frame and has no direct access to the Frame control in the master page.
Here comes the NavigationService property of the Page control, that contains information about the Frame that has navigated to this page, and allows us to directly navigate via the same Frame:
this.NavigationService.Navigate( new Uri( String.Format( "/Views/Item.xaml?title={0}&type={1}", ...), UriKind.Relative ) );
The NavigationContext allows us to access the query string of the current page. For example if I pass some parameters, like the title and the type of my item above, I can use it to get them from the query string:
if ( this.NavigationContext.QueryString.ContainsKey( "type" )
&& this.NavigationContext.QueryString.ContainsKey( "title" ) )
{
string title = this.NavigationContext.QueryString[ "title" ];
string type = this.NavigationContext.QueryString[ "type" ];
}
Urls and DeepLinking
If you have clicked a couple of links in the demo you should have noticed that the url changes according to where you navigate. When navigating, the Frame generates appropriate urls and query strings, so you'd be able to access them via the NavigationContext property and use them further in the context of the current page. Also if you try to copy and paste the url into a new page, when the Silverlight application loads, the Frame control will navigate to the exact page, specified in the url. This means that Silverlight finally supports DeepLinking and allows us to improve the SEO for our applications.
The UriMapper
Now when you have already seen the generated urls, you'd probably say: "They don't look friendly enough." or "There is information in them that I don't want the user to be able to see." There is a solution to this problem too! I introduce you the UriMapper, which allows us to map the urls and display much more user friendly ones in the browser.
In the App.xaml add the following namespace, which contains the UriMapper control:
<Application
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
xmlns:navigationCore="clr-namespace:System.Windows.Navigation;assembly=System.Windows.Controls.Navigation"
x:Class="MiniSilverlight3Show.App">
In the resources I add the following UriMapper with the following mappings:
<navigationCore:UriMapper x:Key="MyMapper">
<navigationCore:UriMapping Uri="Home" MappedUri="/Views/Home.xaml" />
<navigationCore:UriMapping Uri="News" MappedUri="/Views/Items.xaml?type=news" />
<navigationCore:UriMapping Uri="Articles" MappedUri="/Views/Items.xaml?type=article" />
<navigationCore:UriMapping Uri="News/{title}" MappedUri="/Views/Item.xaml?type=news&title={title}" />
<navigationCore:UriMapping Uri="Articles/{title}" MappedUri="/Views/Item.xaml?type=article&title={title}" />
</navigationCore:UriMapper>
The Uri property determines the url that is displayed by the browser and that must be used to navigate in the code and the MappedUri property determines the url that is mapped when the Frame navigates to the specific page. Also notice the mappings for the Item.xaml page, where the title is not a constant. I define it in both the Uri and the MappedUri properties, and the rest of job a leave to the UriMapper. Finally we provide it to our Frame control via the UriMapper proeprty:
<navigation:Frame x:Name="MainContent"
...
UriMapper="{StaticResource MyMapper}">
Conclusion
In this article we have made a simple overview of one of the greatest (for me) features of Silverlight. The Navigation framework allows us to easily navigate between pages, without writing a lot of code or creating custom controls; it supports Browser History integration and DeepLinking, displays adequate urls in the browser and allows us to map them. Actually what more could you want? :)
References
http://silverlight.net/learn/learnvideo.aspx?video=187319 - A nice video by Tim Heuer about the Silverlight 3 Navigation framework
More on Uri Routing by Tim Heuer
Silverlight 3 Navigation API by Thanigainathan Siranjeevi
Silverlight 3: Navigation Application Template Extra themes by Brad Abrams