1. Introduction:
In a previous article we learned how to navigate to another Silverlight page without using Navigation Framework, which is a new feature in Silverlight 3.
So in this article we will learn how to create a navigation experience similar to browsing through pages of a web site. Navigation Framework also allows us to create a history that can integrate with the browser, enabling users to navigate forward and backward through the history using the browser's back and forward buttons. So before we dive deep into programming with Navigation Framework, we need to get to know two main objects that are contained in the Navigation Framework, Page and Frame. The Frame object is very similar to a ContentPlaceHolder in ASP.NET master pages and is the place holder for the different views to be loaded onto the page.
2. Creating a Silverlight Navigation Application.
Step 1: Start Visual Studio 2008 and select File --> New --> Project from the main menu.
Step 2: When the New Silverlight Application dialog appears, select the default to host the Silverlight application in a new ASP.NET web application named NavigationFrmk.Web. Press OK to continue.
Step 3: By default the MainPage.xaml file will be created and opened for editing. We will start by editing that file. In the Grid definition, add ShowGridLines="True" so we can see how our cells are laid out. We can turn this property off later so our application is cleaner
Step 4: Next we want to define the Grid cells. We will simply have two rows, one for the links and one for the navigated content.
<Grid ShowGridLines="True" x:Name="LaWetRoot" Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
</Grid>
Step 5: Now that we have the two rows, we want to add our HyperlinkButtons that will be used to navigate to the different views. We will do this in a horizontal StackPanel. For the Click property, create an event handler called LinkClick.
<Grid ShowGridLines="True" x:Name="LayoutRoot" Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
</Grid>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<HyperlinkButton
Content="View 1"
Click="HyperlinkButton_Click"
Padding="5"
Tag="/Page1">
</HyperlinkButton>
<HyperlinkButton
Content="View 2"
Click="HyperlinkButton_Click"
Padding="5"
Tag="/Page2">
</HyperlinkButton>
</StackPanel>
</Grid>
Step 6: The next step will be to add support for the Navigation Framework in our project. The first step is to add a reference to System.Windows.Controls.Navigation.dll by right clicking on the References folder in our Silverlight project and choosing Add Reference as shown below ;
Step 7: When the Add Reference dialog appears, be sure that the .NET tab is selected and then browse through the list until we find System.Windows.Controls.Navigation, as shown below. Select the entry and press OK to add the reference to the project.
Step 8: When the assembly is added we will see it appear under References in the Solution Explorer, as shown below
Step 9: Now that you have added the reference to the Navigation Framework, we need to add the navigation objects to your application. You will start by adding the XML namespace for System.Windows.Controls.Navigation to the UserControl definition.
Step 10: we can now add a Frame to the bottom row of the root grid named ContentFrame. You will also set the HorizontalContentAlignment and VerticalContentAlignment to Stretch so the Frame will consume the entire Grid Cell. We will also give the Frame a 10 pixel Margin and a BorderThickness to 2 pixels.
<navigation:Frame x:Name="ContentFrame"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
Margin="10"
Grid.Row="1"
BorderThickness="2"
BorderBrush="Black" />
Step 11: Next, you will add the different views to the project. Right-click on the Silverlight project and select Add New Item.
Step 12. On the Add New Item dialog, select the Silverlight Page template, name the page View1.xaml and click on the Add button.
Step 13: Once Page1.xaml has been added, we will repeat steps to add another Silverlight Page named Page2.xaml.
Step 14: Open Page1.xaml up in design mode and add the following XAML to the root Grid.
<Grid x:Name="LayoutRoot">
<TextBlock Text="Page 1"
FontSize="60"
Foreground="Green"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Grid>
Step 15: Open Page2.xaml up in design mode and add the following XAML to the root Grid.
<Grid x:Name="LayoutRoot">
<TextBlock Text="Page 2"
FontSize="60"
Foreground="Red"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Grid>
Step 16: We now have the main page containing the Frame and the two pages that you will load into the Frame. Next, we need to actually load the pages into the Frame. We will do this on the click event of the two HyperlinkButtons. While we can easily do this with two click event handlers, we will actually do it with one. We can set the Tag property of the HyperlinkButton to be the page view source file. Then the click event handler will be able to retrieve the source file from the Tag.
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<HyperlinkButton
Content="View 1"
Click="HyperlinkButton_Click"
Padding="5"
Tag="/Page1.xaml">
</HyperlinkButton>
<HyperlinkButton
Content="View 2"
Click="HyperlinkButton_Click"
Padding="5"
Tag="/Page2.xaml">
</HyperlinkButton>
</StackPanel>
Step 17: Within the event we will add the following code to retrieve the view's source file.
private void HyperlinkButton_Click(object sender, RoutedEventArgs e)
{
HyperlinkButton button = (HyperlinkButton)sender;
string viewSource = button.Tag.ToString();
}
Step 18: Now that we have the view's source file, you can use the Frame's Navigate method to navigate to the proper view.
private void HyperlinkButton_Click(object sender, RoutedEventArgs e)
{
HyperlinkButton button = (HyperlinkButton)sender;
string viewSource = button.Tag.ToString();
ContentFrame.Navigate(new Uri(viewSource, UriKind.Relative));
}
Step 19: We are now ready to run the solution. Select Debug --> Start Debugging or press F5 to run the application. Internet Explorer will open and the application will be displayed, as shown below,
Step 20: Press the View 1 HyperlinkButton at the top of the screen. The content frame will navigate to the Page1.xaml content, as shown below,
3. How to Navigate from One Page to another Silverlight Page.
To accomplish this we will use NavigationService Object, an object that allows a view to access its hosting frame.
Step 1: Let's Open the XAML for Page.xaml and modify the source to include a button under the TextBlock, as below
<Grid x:Name="LayoutRoot">
<StackPanel>
<TextBlock Text="Page 1"
FontSize="60"
Foreground="Green"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
<Button Click="Button_Click"
Padding="10"
Content="Navigate to Inner Page"
HorizontalAlignment="Center" />
</StackPanel>
</Grid>
Step 2: You need to add the new Page that we will navigate to use the NavigationService. Right click on the Silverlight project and choose Add --> New Item. Select Silverlight Page as the template and name the file InnerPage1.xaml.
Step 3: In the XAML for InnerView1.xaml, add a simple TextBlock.
<Grid x:Name="LayoutRoot">
<TextBlock Text="Inner Page 1"
FontSize="40"
Foreground="Blue"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Grid>
Step 4: Next, add the Button_Click event handler in the Page1.xaml code behind and add the following code
private void Button_Click(object sender, RoutedEventArgs e)
{
NavigationService.Navigate(new Uri("/InnerPage.xaml", UriKind.Relative));
}
Step 5: We are now ready to run the solution. Select Debug --> Start Debugging or press F5 to run the application. When Internet Explorer opens the application, click on the View 1 link at the top.
4. How to Pass Data between Navigation Pages.
In this section, we will discuss passing data to page views within a Navigation Framework solution. In HTML pages, data is passed to other pages using the QueryString. The same is true for pages within a Silverlight navigation application through the use of the NavigationContext object. As an example, if we want to retrieve the QueryString property ProductID, we would use the following syntax:
string productId = NavigationContext.QueryString["ProductID"].ToString();
Let's explore how to use the NavigationContext object to pass data to views.
Step 1: Open the XAML for Page1.xaml and modify the source to include a ComboBox under the Button.
<ComboBox Padding="10" Margin="10" x:Name="Color" Width="100">
<ComboBoxItem Content="Blue" IsSelected="True" />
<ComboBoxItem Content="Red" />
<ComboBoxItem Content="Green" />
</ComboBox>
Step 2: Next open the code behind for Page.xaml and edit the Button_Click event handler to pass the selected color in the query string of the Uri passed to the Navigate method.
private void Button_Click(object sender, RoutedEventArgs e)
{
string sColor = Color.SelectionBoxItem.ToString();
NavigationService.Navigate(new Uri(String.Format("/InnerPage.xaml?Color={0}", sColor), UriKind.Relative));
}
Step 3: Open the InnerPage1.xaml file and add a second TextBlock below the existing TextBlock using a StackPanel.
<StackPanel>
<TextBlock Text="Inner Page 1"
x:Name="ViewHeader"
FontSize="40"
Foreground="Blue"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
<TextBlock Text="(Blue)"
x:Name="ViewColor"
FontSize="30"
Foreground="Blue"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</StackPanel>
Step 4: Open the code behind for InnerView1.xaml and retrieve the passed color using the NavigationContext object. Then add a switch statement to change the color of the TextBlocks and edit the Text for the second TextBlock.
protected override void OnNavigatedTo(NavigationEventArgs e)
{
string color = NavigationContext.QueryString["Color"].ToString();
Brush b;
switch (color)
{
case "Red":
b = new SolidColorBrush(Color.FromArgb(255, 255, 0, 0));
ViewHeader.Foreground = b;
ViewColor.Foreground = b;
ViewColor.Text = "(Red)";
break;
case "Green":
b = new SolidColorBrush(Color.FromArgb(255, 0, 255, 0));
ViewHeader.Foreground = b;
ViewColor.Foreground = b;
ViewColor.Text = "(Green)";
break;
default:
b = new SolidColorBrush(Color.FromArgb(255, 0, 0, 255));
ViewHeader.Foreground = b;
ViewColor.Foreground = b;
ViewColor.Text = "(Blue)";
break;
}
}
Step 5: We are now ready to run the solution. Select Debug --> Start Debugging or press F5 to run the application. When Internet Explorer opens the application, click on the Page 1 link at the top. The application should appear, as shown below
5. How to Hide the URL details , i.e. Uri Mapping
In the preceding examples, we noticed the URL changing as you navigated to different Views in a frame. We also noticed that the URLs were not very pretty and contained some information that we may not want to display. As an example, consider the following URL:
http://www.domain.com/Catalog.aspx#ProductDetails.xaml?ID=4
For starters, this URL is not very pleasant to look at, and not very user-friendly either. It also may contain information that we would prefer not to provide the user, such as the exact filename and the query string name. A much more appropriate URL would look like the following:
http://www.domain.com/Catalog.aspx#Product/4.
So let's try out how to use URIMapping with Navigation Framework.
Step 1: There are three views in our solution that you would like to add Uri Mapping for: Page1.xaml, Page2.xaml, and InnerPage.xaml. For these, we will add simple Uri Maps that point these to Page1, Page2, and InnerView. Let's start by opening the App.xaml file and adding the xml namespace for the navigation framework.
<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="NavigationFrmk.App"
xmlns:navigation="clr-namespace:System.Windows.Navigation;assembly=System.Windows.Controls.Navigation">
</Application>
Step 2: Now that the namespace is added, we need to add the UriMapper section to the Application Resources.
<Application.Resources>
<navigation:UriMapper x:Key="uriMapper">
</navigation:UriMapper>
</Application.Resources>
Step 3: Within the UriMapper section we now need to add two UriMapping elements, one for Page1.xaml and one for Page2.xaml. Each mapping will contain two attributes: The Uri attribute is the name representing the mapping that will appear in the browser address bar, and the MappedUri attribute represents the actual Uri mapped to by the UriMapping.
<Application.Resources>
<navigation:UriMapper x:Key="uriMapper">
<navigation:UriMapping Uri="/Page1" MappedUri="/Page1.xaml"></navigation:UriMapping>
<navigation:UriMapping Uri="/Page2" MappedUri="/Page2.xaml"></navigation:UriMapping>
</navigation:UriMapper>
</Application.Resources>
Step 4: You can update MainPage.xaml to navigate to the views using the UriMappings.
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<HyperlinkButton
Content="View 1"
Click="HyperlinkButton_Click"
Padding="5"
Tag="/Page1">
</HyperlinkButton>
<HyperlinkButton
Content="View 2"
Click="HyperlinkButton_Click"
Padding="5"
Tag="/Page2">
</HyperlinkButton>
</StackPanel>
You notice here, we just changed Tag attribute from page1.xaml to page.xaml respectively.
Step 5: Next, we will shift your attention to the InnerPage.xaml. If you recall in the previous section on passing data to a navigation view, we were passing the color to InnerPage.xaml via the QuervString. Because of this, we need that to be taken into account in your UriMapping. Open up the code behind for Page1.xaml and modify the Button_Click method so it navigates to InnerView/{0}.
private void Button_Click(object sender, RoutedEventArgs e)
{
string sColor = Color.SelectionBoxItem.ToString();
//Old URL
//NavigationService.Navigate(new Uri(String.Format("/InnerPage.xaml?Color={0}", sColor), UriKind.Relative));
//New URL
NavigationService.Navigate(new Uri(String.Format("/InnerPage/{0}", sColor), UriKind.Relative));
}
Step 6: In order for this navigates to work, we need to add an additional UriMapping to the Application.Resources.
<Application.Resources>
<navigation:UriMapper x:Key="uriMapper">
<navigation:UriMapping Uri="/Page1" MappedUri="/Page1.xaml"></navigation:UriMapping>
<navigation:UriMapping Uri="/Page2" MappedUri="/Page2.xaml"></navigation:UriMapping>
<navigation:UriMapping Uri="/InnerPage/{c}" MappedUri="/InnerPage.xaml?Color={c}"></navigation:UriMapping>
</navigation:UriMapper>
</Application.Resources>
Step 7: Next, in the MainPage.xaml, add the UriMapper property to the Navigation Frame object.
<navigation:Frame x:Name="ContentFrame"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
Margin="10"
Grid.Row="1"
BorderThickness="2"
BorderBrush="Black"
UriMapper="{StaticResource uriMapper}"/>
Step 8: We are now ready to run the solution. Select Debug --> Start Debugging or press F5 to run the application. When Internet Explorer opens the application, click on the View 1 link at the top. Notice that the URL now reads:
http://localhost:3676/NavigationFrmkTestPage.aspx#/Page1
http://localhost:3676/NavigationFrmkTestPage.aspx#/InnerPage/Blue
As you have seen in this example, UriMapping provide a way to create more user friendly Url addresses and also provide a way to hide application specific information from appearing in your application.
6. Auto Integration with Browser History:
The navigation features of the Frame control also integrate with the browser. Each time you call the Navigate() method, Silverlight adds a new entry in the history list . The first page of your application appears in the history list first, with the title of the HTML entry page. Each subsequent page appears under that in the history list, using the user-control file name for the display text (such as Page1.xaml).
7. Conclusion:
Here in this article we learned how to use Navigation Framework from scratch. We learned featured like, Page and Frame, Passing values between pages URI Mapping.
Hope it did some needful.
Cheers!