Silverlight
Navigation Overview

[Note: This topic is pre-release documentation and is subject to change in future releases. Blank topics are included as placeholders.]

Unlike Windows Presentation Foundation (WPF), Silverlight does not currently provide a built in navigation system nor automatic integration with browser navigation. However, Silverlight does provide several features that you can use to implement your own solutions.

This topic describes common navigation scenarios and issues, and provides guidance about how to add navigation features to your application.

Navigation with Silverlight can mean one of two things:

  • Browser navigation.

  • Application navigation.

Browser Navigation

With browser navigation, your application can provide direct links to other Web pages. Browser navigation is useful to provide access to resources external to your application. You can also use browser navigation with Silverlight to implement controls such as side-bar menus for use with ordinary Web pages.

To enable user navigation to other Web pages, you can use the HyperlinkButton control and set its NavigateUri property. By default, the HyperlinkButton looks and behaves like an HTML hyperlink. You can use it for navigating the current browser window, or you can set the TargetName property to open a new browser window. You can also use HyperlinkButton for application navigation by leaving NavigateUri empty and handling the Click event instead.

The following code example demonstrates the use of HyperlinkButton for browser navigation.

XAML
<HyperlinkButton NavigateUri="http://www.microsoft.com"
    Content="Go to Microsoft" TargetName="_new" />

To navigate the browser programmatically, you can manipulate the HTML DOM through the HtmlPage class, as shown in the following example.

XAML
        <HyperlinkButton Content="Go to Microsoft" Click="GoToMicrosoft" />
Visual Basic
Private Sub GoToMicrosoft(ByVal sender As System.Object, _
    ByVal e As System.Windows.RoutedEventArgs)

    If (HtmlPage.IsPopupWindowAllowed) Then
        HtmlPage.PopupWindow( _
            New Uri("http://www.microsoft.com"), Nothing, Nothing)
    Else
        HtmlPage.Window.Navigate(New Uri("http://www.microsoft.com"))
    End If

End Sub
C#
private void GoToMicrosoft(object sender, RoutedEventArgs e)
{
    if (HtmlPage.IsPopupWindowAllowed)
    {
        HtmlPage.PopupWindow(new Uri("http://www.microsoft.com"), null, null);
    }
    else
    {
        HtmlPage.Window.Navigate(new Uri("http://www.microsoft.com"));
    }
}
NoteNote:

Access to the HTML DOM is enabled by default only when your Silverlight application and its host page are served from the same domain. Access is disabled by default when the application and host page are served from different domains. Host pages can set the enableHtmlAccess property when embedding the control to explicitly enable or disable HTML DOM access from your application. For more information, see Security Settings in HTML Bridge.

Application Navigation

With application navigation, your application splits its content into multiple units or pages among which your users can navigate. Application content blocks are called pages by analogy to Web pages. In Silverlight, you will typically implement pages as user controls.

The UserControl class is a convenient container for pages that you can design in XAML. The Silverlight application template in Visual Studio generates a default UserControl named Page, which includes a Page.xaml file and a code-behind file. You can add new pages to your application by using the Silverlight user control template in the Add New Item dialog box. For more information about Visual Studio projects, see How to: Create a New Silverlight Project.

The initial page of your application is used to set the Application..::.RootVisual property. You can only set RootVisual one time, so the initial page becomes the permanent application root.

You can design the root page to contain a content area plus permanent user-interface (UI) components, such as headers, footers, and navigation sidebars. Alternately, you can use the root page as an outer container only. In this case, you put all UI components into separate pages, and then nest them within the root page as needed to create your layout.

The outer content of a UserControl is usually a Grid or other layout panel named LayoutRoot by convention. You can implement application navigation within any UserControl by manipulating the layout root's Children collection. For a simple example, you can add a TabControl to the layout root and display additional pages within different tabs. Alternately, you can perform navigation by adding a new page to the layout root and removing the previous contents.

The following code example demonstrates how to implement simple navigation by replacing the contents of the layout root.

XAML
<HyperlinkButton Content="Go to Page 2" 
    Click="GoToPage2UsingContentSwap" />
Visual Basic
Private Sub GoToPage2UsingContentSwap(ByVal sender As Object, ByVal e As RoutedEventArgs)
    Dim rootVisual As Page = DirectCast(Application.Current.RootVisual, Page)
    rootVisual.LayoutRoot.Children.Clear()
    rootVisual.LayoutRoot.Children.Add(New Page2())
End Sub
C#
private void GoToPage2UsingContentSwap(
    object sender, RoutedEventArgs e)
{
    Page rootVisual = (Page)Application.Current.RootVisual;
    rootVisual.LayoutRoot.Children.Clear();
    rootVisual.LayoutRoot.Children.Add(new Page2());
}

By clearing the layout root's contents before you add a new page, you can free the previous page for garbage collection. This is useful to maintain performance when users navigate through multiple complex pages and rarely return to previous pages.

If you want to keep pages loaded in memory for fast retrieval, you can store references in variables external to the navigation method. Another option is to load multiple pages into the layout root and change their Visibility property values to perform navigation. The following example code demonstrates this structure. This code assumes that the project is named ApplicationNavigation and contains two UserControl-derived classes named Page1 and Page2.

XAML
<!-- in Page.xaml -->
<Grid x:Name="LayoutRoot" Background="White" 
    xmlns:local="clr-namespace:ApplicationNavigation">

    <local:Page1 x:Name="Page1" />
    <local:Page2 x:Name="Page2" Visibility="Collapsed"/>

</Grid>
XAML
<!-- in Page1.xaml -->
<HyperlinkButton Content="Go to Page 2"
    Click="GoToPage2UsingVisibilitySwap" />
Visual Basic
Private Sub GoToPage2UsingVisibilitySwap(ByVal sender As Object, ByVal e As RoutedEventArgs)
    Dim rootVisual As Page = DirectCast(Application.Current.RootVisual, Page)
    rootVisual.Page1.Visibility = Visibility.Collapsed
    rootVisual.Page2.Visibility = Visibility.Visible
End Sub
C#
private void GoToPage2UsingVisibilitySwap(
    object sender, RoutedEventArgs e)
{
    Page rootVisual = (Page)Application.Current.RootVisual;
    rootVisual.Page1.Visibility = Visibility.Collapsed;
    rootVisual.Page2.Visibility = Visibility.Visible;
}        

When your application uses more than a few pages, you will typically move the navigation code into a dedicated navigation manager class for added convenience. As your application grows in complexity, you might want to add other features, such as URL support, animated transitions, and on-demand loading of remotely stored pages.

Application Navigation vs. Browser Navigation

When you implement application navigation, it is important to understand how it relates to normal browser navigation. There are two major issues:

  • Silverlight does not provide automatic URL support (also known as deep linking) for application pages. Without URL support, users cannot bookmark or link to specific pages within your application like they can with ordinary Web pages.

  • Silverlight does not provide automatic integration between application navigation and browser navigation. Clicking the browser back or forward buttons can navigate the browser to another Web page, unloading the Silverlight plug-in.

As far as a Web browser is concerned, a Silverlight application is hosted on a single Web page with a single URL. Navigation away from the host URL will cause the plug-in to unload and lose your application state. Navigation back to the host URL will reload the plug-in and your application with the initial state as configured in the Web page.

URL Support

You can use the plug-in configuration to specify a page to load at startup. However, you can also ignore the configuration settings and load a startup page based on a URL parameter value.

URL support primarily requires that each page have a unique identifier that you can use as a URL parameter value. For example, with the simple navigation described earlier in this topic, you can identify pages by using the numbers in the type names. The following code example provides a simple demonstration of this process.

Visual Basic
Private Sub Application_Startup(ByVal o As Object, _
    ByVal e As StartupEventArgs) Handles Me.Startup

    Me.RootVisual = New Page()

    ' Determine whether the URL includes a "page" parameter. 
    If HtmlPage.Document.QueryString.Keys.Contains("page") Then
        Dim startPage As String = HtmlPage.Document.QueryString("page")
        Dim root As Page = TryCast(RootVisual, Page)

        ' If there is a page parameter set to "2", navigate to page 2. 
        If startPage.Equals("2") Then
            root.Page1.Visibility = Visibility.Collapsed
            root.Page2.Visibility = Visibility.Visible
        End If
    End If

End Sub
C#
private void Application_Startup(object o, StartupEventArgs e) 
{ 

    this.RootVisual = new Page(); 

    // Determine whether the URL includes a "page" parameter. 
    if (HtmlPage.Document.QueryString.Keys.Contains("page")) { 
        string startPage = HtmlPage.Document.QueryString["page"]; 
        Page root = RootVisual as Page; 

        // If there is a page parameter set to "2", navigate to page 2. 
        if (startPage.Equals("2")) { 
            root.Page1.Visibility = Visibility.Collapsed; 
            root.Page2.Visibility = Visibility.Visible; 
        } 
    } 

} 

Of course, you will also have to provide a way for users to retrieve the URLs (including the page parameter values) for particular application pages. You could display an application address bar, for example, or provide the URL of the current page from a menu option.

This is where better browser integration would be useful. Ideally, you would display the application page's URL in the browser address bar, which you would update every time that application navigation occurs. This would give each application page an entry in the browser navigation history. Of course, you would also want to intercept browser navigation events to perform application navigation. Otherwise, the plug-in would unload and reload every time navigation occurs just to display a new application page at each startup.

You could use the Silverlight HTML Bridge and JavaScript to implement this kind of deep browser integration. Unfortunately, the details are different for different browsers, introducing complexity and maintenance issues that are outside the scope of this topic. For more information, see Additional Navigation Resources.

Preventing Accidental Browser Navigation

If you do not want to integrate with the Web browser navigation system, you should ensure that your application navigation controls are distinct from the browser navigation controls. This will discourage users from navigating the browser accidentally. Fortunately, there are simple ways to do this.

The layout of your host Web page is a major consideration. Users are more likely to use the browser back and forward buttons if your layout, content, and navigation system reminds them of a traditional Web page. In particular, if your application uses the entire browser window, then the distinction between the browser and your application becomes much less clear.

One workaround for this problem is to open a new browser window to display pages that host full-window applications. The new browser window will not have any navigation history, so the back and forward buttons will be disabled. Of course, if you implement deep linking, you will probably want to redirect specific page requests to a new browser window, passing the URL parameter.

See Also

Concepts

Other Resources

Page view tracker