In any application there will be many pages and user controls to display the
content to the users. Also content will be displayed based on the some variable
values, which may be passed from one page another page by using session and
query string parameters. So, question comes here is how does Silverlight
navigation works? How do we pass query string parameters from one page to
another page?
Silverlight Navigation framework
In Silverlight, We will be implement application/site navigation using the Frame
and Page controls. Page controls correspond to separate sections of content, but
whereas frame is container for page controls, and provides navigation across
pages controls. That states, frame display one page content at a time. We will
be learning about the frame control more in details. It has got big picture to
learn in both declarative and programmatic.
Frame
In Silverlight, Frame is a Control to support the Navigation, either to or from,
across the xaml's page controls. We need to reference to
System.Windows.Controls.Navigation dll and its namespace is
System.Windows.Controls.
We will be creating many different Silverlight pages to present the content in
our application and then navigate to those pages from the frame. When a Uniform
Resource Identifier is requested, either programmatically or through a user
action, the frame navigates to the page that matches the URI.
The requested URI can include the page to display and also values that represent
a particular state for the page. But within the page, we need provide logic to
process the URI values and create the page in the correct state.
<sdk:Frame
x:Name="employeeModuleContentFrame"
Source="/EmployeeHome"
<sdk:Frame.UriMapper>
<sdk:UriMapper>
<sdk:UriMapping
Uri=""
MappedUri=""/>
.
.
</sdk:UriMapper>`
</sdk:Frame.UriMapper>
</sdk:Frame>
The Source Property here helps us to define the default page to be displayed. We
will see at what are UriMapper and UriMapping class details at basic.
UriMapper Class
UriMapper class contains the collection of UriMapping objects. That actually
converts a uniform resource identifier (URI) into a new URI based on the rules
of a matching object specified in a collection of mapping objects.
UriMapping Class
Using UriMapping class we can define the pattern for converting a requested URI
to a Mapped or resolved URI. We will see some examples of the patterns and how
they are resolved. When we create a navigation application in VSTS 2010
following is the default navigations available. Let us see what is this first. I
just removed style and events.
<Grid
x:Name="LayoutRoot"
Style="{StaticResource
LayoutRootGridStyle}">
<Border
x:Name="ContentBorder"
Style="{StaticResource
ContentBorderStyle}">
<navigation:Frame
x:Name="ContentFrame"
Source="/Home">
<navigation:Frame.UriMapper>
<uriMapper:UriMapper>
<uriMapper:UriMapping
Uri=""
MappedUri="/Views/Home.xaml"/>
<uriMapper:UriMapping
Uri="/{pageName}"
MappedUri="/Views/{pageName}.xaml"/>
</uriMapper:UriMapper>
</navigation:Frame.UriMapper>
</navigation:Frame>
</Border>
<Grid
x:Name="NavigationGrid">
<Border
x:Name="BrandingBorder"
>
<StackPanel
x:Name="BrandingStackPanel">
<TextBlock
x:Name="ApplicationNameTextBlock"
Text="Application
Name"/>
</StackPanel>
</Border>
<Border
x:Name="LinksBorder"
>
<StackPanel
x:Name="LinksStackPanel">
<HyperlinkButton
x:Name="Link1"
NavigateUri="/Home"
TargetName="ContentFrame"
Content="home"/>
<HyperlinkButton
x:Name="Link2"
NavigateUri="/About"
TargetName="ContentFrame"
Content="about"/>
</StackPanel>
</Border>
</Grid>
</Grid>
We have two patterns by default, one yellow highlighted and Gray color is the
second one. Assume that our application URL is
http://localhost:2904/SilverlightApplicationTestPage.aspx
When we type the above URL and press enter in the browser address bar, what
happens now, or what should be displayed here as a default. Here we have not
requested for any page so the URI is empty. So the UriMapping pattern matching
is
<uriMapper:UriMapping
Uri=""
MappedUri="/Views/Home.xaml"/>
<navigation:Frame
x:Name="ContentFrame"
Source="/Home">
And also we have Source Property of the Frame set to "/Home", so it picks up the
MappedUri and displays the Home.xaml from the view folder. Now you can notice
the browser URL as http://localhost:2904/SilverlightApplicationTestPage.aspx#/Home
which is user friendly.
Now let us do one thing, to test the pattern, remove the Source property of the
Frame control and test the page. We can notice that Home page still displayed
but browser url is different, i.e. http://localhost:2904/SilverlightApplicationTestPage.aspx,
this is because the Uri pattern.
Now click on the about link, next home, what happens and why? Let us see. If you
see the xaml for about, as bellow. We are requesting for About.
<HyperlinkButton
x:Name="Link2"
NavigateUri="/About"
TargetName="ContentFrame"
Content="about"/>
Now see which pattern matches to it. If see the first navigation pattern where
Uri="", that mean when the there no specific request for the URI this particular
navigation pattern will match. Coming to the second pattern, following
<uriMapper:UriMapping
Uri="/{pageName}"
MappedUri="/Views/{pageName}.xaml"/>
Uri is referring to {pageName} which is a parameter, when we click on the about
link we are requesting for "/About" which will be parameter to the Uri and for
the MappedUri so the request maps to the NavigateUri. That is
Uri ="/About"
MappedUri="/Views/About.xaml"
Let us Add a new one to it. Name it as NewPage.xaml, and assume that we will be
having many page with the pattern like {page}Page.xmal in future. Now what will
be the pattern for the same?
Comment out the second navigation pattern, and Add the following Uri pattern to
the UriMapping.
<uriMapper:UriMapping
Uri="/{pageName}"
MappedUri="/Views/{pageName}Page.xaml"/>
Add following link to the links section in xaml
<HyperlinkButton
x:Name="Link3"
NavigateUri="/New"
TargetName="ContentFrame"
Content="New"/>
Run the application and see what happens after clicking on "new", it works. See
the new pattern that we added. "new" is the parameter now Uri become "/New" and
the MappedUri becomes "/Views/NewPage.xaml". Now click on the home or about it
will throw an error because the there is no mating pattern.
Ensure that we can't have following patterns at a time. Because when we click on
about or home first pattern also matches but there is no page called New.xaml,
so it won't work. So be careful on deciding the page name standards .
<uriMapper:UriMapping
Uri="/{page}"
MappedUri="/Views/{page}.xaml"/>
<uriMapper:UriMapping
Uri="/{pageName}"
MappedUri="/Views/{pageName}Page.xaml"/>
So, this way we can avoid declaring many mapping tags to the UriMapper object.
Same explanation goes for home link as well. Now we know what is user friendly
URL's, Mapping Uri's and mapped Uri's. Now let us see more patterns. Now let us
see more patterns by passing query string parameters, which will be using more
frequently in our application.
There are many more patterns which will help us in the Navigation across pages.
Refer to
http://msdn.microsoft.com/en-us/library/cc838245(VS.95).aspx
Passing Query String Parameters
Assume we have Employee List Page, like employee search that displays the list
of employees. Upon selection and by clicking on one button we need to pass the
selected employee if to employee details page, where we will be displaying the
employee details. Here search for employees and grid selection is out of scope
of the context. What I will be doing is upon clicking on the button how we will
be passing the parameter by using a navigation pattern.
- Add a new page called EmployeePage.xaml to the View Folder
- Add a text block, , lblSelectedEmpID, in which we will display the selected
employee.
- Add a Button to the MainPage.xaml, btnEmployeeDetails.
- Add the following code to the Button click event and Add the following code.
private
void btnEmployeeDetails_Click(object
sender, RoutedEventArgs e)
{
Uri uri =
new Uri("/EmployeePage?empId=10",UriKind.Relative);
this.ContentFrame.Navigate( uri);
}
- Add the following code to the EmployeePage.xaml
protected
override void
OnNavigatedTo(NavigationEventArgs e)
{
if
(this.NavigationContext.QueryString.ContainsKey("empId"))
{
this.lblSelectedEmpID.Text
= "Selected Employee ID is : " +
this.NavigationContext.QueryString["empId"].ToString();
}
}
- Run the application and test it.
Frame Events
Frame control has two main events, one is Navigated and NavigationFailed. We
will see what they are how to use them in our Silverlight navigation.
Navigation Failed Event
I would like to cover Navigation Failed event first. Because, if the page that
we are requesting is not found or invalid path had been given we will need to
handle the error.
Add the following event to the Frame in our xaml and code behind.
<navigation:Frame
x:Name="ContentFrame"
NavigationFailed="ContentFrame_NavigationFailed"
>
// UriMapper
and UriMapping goes here
</navigation:Frame>
// If an
error occurs during navigation because of invalid path or page not found
private
void ContentFrame_NavigationFailed(object
sender, NavigationFailedEventArgs e)
{
}
Some of the important point we need to know is
- Handled -> When we handle NavigationFailed event to process an exception that
is thrown as a result of a failed navigation, and we don't want Silverlight to
continue processing the exception, you should set the Handled property to true,
which is by default false.
- Uri -> gets the uniform resource identifier (URI) that could not be navigated
to.
So our code becomes, change btnEmployeeDetails click event by giving wrong xaml
page path and test the code.
private void
ContentFrame_NavigationFailed(object sender,
NavigationFailedEventArgs e)
{
e.Handled = true;
MessageBox.Show(e.Exception.Message.ToString()
+ " \n " + e.Uri);
}
If you need to display a nice user friendly message there are many techniques
available in Silverlight like child window or new page itself, for now out of
scope.
Navigated Event
Now we will see about Navigated event. This event occurs, if we implement, when
the requested Uri is found and available. The event arguments object provides
data for the OnNavigatedTo and OnNavigatedFrom methods, and handlers of the
Navigated and NavigationStopped events.
The data that it provides is Content and Uri. Content get the content of target
and Uri get the target Uri.