在Silverlight里,导航框架允许开发者在Silverlight应用程序里实现一种方式来跳转到不同的页面,就像网站上的不同页面一样。这个框架也允许开发者创建历史使其与浏览器结合,使用户能使用浏览器的向前和向后导航。
导航框架的两个主要对象是Frame和Page对象。Frame与ASP.NET母版页中的ContentPlaceHolder非常相似,是在一个页面放置不同views的地方。
在这个练习里,会创建一个简单的应用程序包含两个超链接按钮和一个Frame。点击超链接会加载两个页面中的一个到Frame。Lets Go。
<Grid x:Name="LayoutRoot" Background="White" ShowGridLines="True"> <Grid.RowDefinitions> <RowDefinition Height="30" /> <RowDefinition></RowDefinition> </Grid.RowDefinitions> <StackPanel Orientation="Horizontal" HorizontalAlignment="Center"> <HyperlinkButton Content="View 1" Click="LinkClick" Padding="5" /> <HyperlinkButton Content="View 2" Click="LinkClick" Padding="5" /> </StackPanel> </Grid>
<UserControl x:Class="NavAppFromScratch.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:nav="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400">
<nav:Frame x:Name="ContentFrame" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" Margin="10" Grid.Row="1" BorderThickness="2" BorderBrush="Black"/>
<Grid x:Name="LayoutRoot"> <TextBlock Text="View 1" FontSize="60" Foreground="Green" HorizontalAlignment="Center" VerticalAlignment="Center" /> </Grid>
<Grid x:Name="LayoutRoot"> <TextBlock Text="View 2" FontSize="60" Foreground="Blue" HorizontalAlignment="Center" VerticalAlignment="Center" /> </Grid>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center"> <HyperlinkButton Content="View 1" Click="LinkClick" Tag="/Page1.xaml" Padding="5" /> <HyperlinkButton Content="View 2" Click="LinkClick" Tag="/Page2.xaml" Padding="5" /> </StackPanel>
private void LinkClick(object sender, RoutedEventArgs e) { HyperlinkButton button = (HyperlinkButton)sender; string viewSource = button.Tag.ToString(); ContentFrame.Navigate(new Uri(viewSource, UriKind.Relative)); }
Silverlight4对比前一版本有了大幅改进,增加了一堆新特性,例如浏览器历史支持和深度链接(deep linking)。
Silverlight4的另一个优点是支持深度链接。深度链接是链接到应用程序的一个特殊状态页面的能力。
为了解析深度链接,假设有个应用程序已经加载和显示了主页。当用户点击主页上的链接时,应用程序导航到产品列表页面。这时用户可以点击导航到一个产品的详细页面。这个应用程序可以用以下图表示:
如果你想有个链接直接导航到产品B的详细页面?使用导航框架,Silverlight允许开发者在应用程序里链接到不同的状态。
前面那一节里,使用了Frame对象的Navigate方法改变页面。这需要一次又一次地访问寄宿在页面内的Frame对象。例如,考虑下图,你可以从主页轻松导航到View1.但是你想在View1的后置代码里转到Inner View1的话,你需要访问寄宿在View1的Frame对象来导航到Inner View1。
好在,Silverlight的导航框架包含一个可以访问寄宿这View的Frame对象的对象。这个对象就是NavigationService。下面通过练习学习使用NavigationService对象。
这个练习是在前面练习基础上的,需要在Page1里添加一个按钮和使用NavigationService对象导航到InnerView1的点击事件。
<StackPanel> <TextBlock Text="View 1" FontSize="60" Foreground="Green" HorizontalAlignment="Center" VerticalAlignment="Center" /> <Button Click="Button_Click" Padding="10" Content="Navigate to Inner View" HorizontalAlignment="Center" /> </StackPanel>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Background="Black"> <TextBlock Text="Inner View 1" FontSize="40" Foreground="White" HorizontalAlignment="Center" VerticalAlignment="Center"/> </StackPanel>
private void Button_Click(object sender, RoutedEventArgs e) { NavigationService.Navigate(new Uri("/InnerPage1.xaml", UriKind.Relative)); }
这一节,学习了怎样使用NavigationService实现Silverlight页面的导航,下一节,将会学习使用NetworkContext对象在页面之间传递数据。
在HTML页面,可以通过QueryString来传递数据到另一个页面。而在Silverlight应用程序是通过NavigationContext对象来传递数据的。例如,下面代码可以获得一个ProductID:
string productId = NavigationContext.QueryString["ProductID"].ToString();
在这个练习继续使用上节的项目,这里将会传递一些数据到InnerPage1.xaml里。
<StackPanel> <TextBlock Text="View 1" FontSize="60" Foreground="Green" HorizontalAlignment="Center" VerticalAlignment="Center" /> <Button Click="Button_Click" Padding="10" Content="Navigate to Inner View" HorizontalAlignment="Center" /> <ComboBox Padding="10" Margin="10" x:Name="Color" Width="100"> <ComboBoxItem Content="Blue" IsSelected="True" /> <ComboBoxItem Content="Red" /> <ComboBoxItem Content="Green" /> </ComboBox> </StackPanel>
private void Button_Click(object sender, RoutedEventArgs e) { string color = Color.SelectionBoxItem.ToString(); var uri = string.Format("/InnerPage1.xaml?Color={0}", color); NavigationService.Navigate(new Uri(uri, UriKind.Relative)); }
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" > <StackPanel Background="Black"> <TextBlock Text="Inner View 1"x:Name="ViewHeader" FontSize="40" Foreground="White" HorizontalAlignment="Center" VerticalAlignment="Center"/> </StackPanel> <TextBlock Text="(Blue)" x:Name="ViewColor" FontSize="30" Foreground="Blue" HorizontalAlignment="Center" VerticalAlignment="Center" /> </StackPanel>
protected override void OnNavigatedTo(NavigationEventArgs e) { var color = NavigationContext.QueryString["Color"]; 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; } }
这一节学习了通过QueryString的方式使用NavigationContext对象来传递数据。下一节探讨Uri的映射和怎么创建友好的uri来导航页面。
上面的练习里,你可能注意到在Frame里导航到不同页面时,浏览器的URL会改变。可能也会注意到这些URL并不怎么好看,还包含了一些你可能不想显示的信息,例如下面的链接:
http://www.domain.com/Catalog.aspx#ProductDetails.xaml?ID=4
如果链接改为下面这样会好很多:
http://www.domain.com/Catalog.aspx#Product/4
这个URL易读很多,更加友好。而且,它不会透露你应用程序的细节,可以通过使用Uri映射的特性来获得这个链接。
这个练习里,将上面的项目改为使用Uri映射的方式来导航。
<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:nav="clr-namespace:System.Windows.Navigation;assembly=System.Windows.Controls.Navigation" x:Class="NavAppFromScratch.App" >
<Application.Resources> <nav:UriMapper x:Key="uriMapper"> <nav:UriMapping Uri="Page1" MappedUri="/Page1.xaml"/> <nav:UriMapping Uri="Page2" MappedUri="/Page2.xaml"/> <nav:UriMapping Uri="InnerPage/{c}" MappedUri="/InnerPage1.xaml?Color={c}" /> </nav:UriMapper> </Application.Resources>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center"> <HyperlinkButton Content="View 1" Click="LinkClick" Tag="Page1" Padding="5" /> <HyperlinkButton Content="View 2" Click="LinkClick" Tag="Page2" Padding="5" /> </StackPanel>
private void Button_Click(object sender, RoutedEventArgs e) { string color = Color.SelectionBoxItem.ToString(); var uri = string.Format("InnerPage/{0}", color); NavigationService.Navigate(new Uri(uri, UriKind.Relative)); }
<nav:Frame x:Name="ContentFrame" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" Margin="10" Grid.Row="1" BorderThickness="2" BorderBrush="Black"
UriMapper="{StaticResource uriMapper}"/>
除了Uri映射外,Silverlight的导航框架还支持Uri路由。例如,如果你把所有页面放在名为“Views”的文件夹里,你可以按照这个命名约定设置理由映射:
<nav:UriMapping Uri="{}{p}" MappedUri="/Views/{p}.xaml" />
这个映射可以匹配所有在“Views”里的xaml文件。例如,View1可以匹配/Views/Views1.xaml。