科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件用WPF构建强大的用户体验

用WPF构建强大的用户体验

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

标准的应用程序自然地支持菜单驱动导航,而浏览器应用程序自然地支持超链接导航。但是Windows Presentation Foundation应用程序模型能够让两者混合。

作者:陶刚编译 来源:天极开发 2007年11月3日

关键字:

  • 评论
  • 分享微博
  • 分享邮件
导航窗体(NavigationWindow)

  现在你可能对几个问题很疑惑。由于页面不是窗体,那么寄宿页面的窗体来自哪儿?当我们点击超链接的时候,到底是什么在处理导航?HTML Web页面内容是如何显示在Windows Presentation Foundation应用程序中的?所有的这些都是由NavigationWindow来处理的。

  当你把Application.StartupUri设置为XAML或HTML页面的时候,应用程序(我们知道这些页面都不会提供自己的窗口)建立一个NavigationWindow实例来寄宿它们。

  NavigationWindow衍生自Window,并扩展了它的可视化外表,使它的样子与浏览器类似,如图6所示。


图6:NavigationWindow

  当用户点击XAML页面上的超链接的时候,超链接要求NavigationWindow导航到特定的URI。NavigationWindow就载入URI所指向的页面,从而实现寄宿它。被载入页面的URI位置会存储在NavigationWindow.Source属性中,被载入页面的内容在NavigationWindow.Content属性中。

  当内容发生改变的时候,就进行导航,并且把之前的内容添加到导航历史中。这个过程也是由NavigationWindow管理的。导航UI为导航操作提供了两个按钮和一个下拉列表。请注意,你不仅仅可以使用NavigationWindow的默认样式,使用Windows Presentation Foundation支持的多种样子,你还可以轻易地建立自己的导航UI。

  到目前为止,我为你介绍了如何使用标记来配置需要导航的超链接URI。但是,有时候你无法宣告式地决定导航。例如,如果希望查看订单,你就必须建立一个页面实例,并把自己希望查看的订单传递给它。这是无法宣告式地完成的。作为代替,你必须使用代码,如图7所示。

  图7:用代码导航

HomePage.xaml (markup)
<Page ... >
...
<Hyperlink Click="viewHyperlink_Click">
View
</Hyperlink>
...
</Page>

HomePage.xaml.cs (codebehind)
public partial class HomePage : Page
{
 void viewHyperlink_Click(object sender, RoutedEventArgs e)
 {
  // 查看订单
  ViewOrderPage page = new ViewOrderPage(GetSelectedOrder());
  NavigationWindow window = (NavigationWindow)this.Parent; // Don't do this!
  window.Navigate(page);
 }

 Order GetSelectedOrder()
 {
  return (Order)this.ordersListBox.SelectedItem;
 }
 ...
}

  当超链接被点击的时候,它的Click事件处理程序获取当前选中的订单,在实例化的过程中把它传递给ViewOrderPage,并调用它的宿主NavigationWindow的Navigate方法,接着它把页面作为对象而不是URI进行导航。

  你可能发现获取宿主NavigationWindow的引用有些古怪。这是必然的,因为页面没有任何可用于了解自己所寄宿的内容的外部信息。页面可以使用自己的Parent属性来检测宿主,但是Parent返回的是DependencyObject引用,而不是特定宿主类型的强类型(strongly typed)引用。因此,把Parent转换为特定的类型意味着页面知道谁可以寄宿它。但是,你会发现页面可以拥有多种宿主类型。因此,如果你打算让多种宿主类型寄宿自己的页面,你就需要一个与宿主无关的编程执行导航的方法。

  导航服务(NavigationService)

  在Windows Presentation Foundation中,页面和页面宿主之间的分离是由NavigationService实现的,它实现了导航引擎的基本功能,包括导航、导航历史、导航生命周期、内容、为部分内容查找导航服务。如下代码显示了NavigationService类型的基本成员。NavigationWindow并没有真正地实现自己的导航引擎;它是用自己的NavigationService实例来实现的。

  代码:NavigationService类型的基本成员

sealed class NavigationService : IContentContainer
{
 // 导航
 public bool Navigate(Uri source); // 导航到URI
 public void Refresh(); // 重新导航到当前内容
 public void StopLoading(); // 停止当前的导航 // 导航历史
 public bool CanGoBack { get; } // Content in back nav. history?
 public bool CanGoForward { get; } // Content in forward nav. history?
 public void GoBack(); // Go to previous content in nav. history
 public void GoForward(); // Go to next content in nav. history

 // 导航的生命周期
 // 导航请求
 public event NavigatingCancelEventHandler Navigating;
 // 导航到内容
 public event NavigatedEventHandler Navigated;
 // 内容载入了
 public event LoadCompletedEventHandler LoadCompleted;
 // 导航错误
 public event NavigationFailedEventHandler NavigationFailed;
 // 下载的字节数
 public event NavigationProgressEventHandler NavigationProgress;
 // 导航停止了
 public event NavigationStoppedEventHandler NavigationStopped;

 // 内容
 public object Content { get; set; } // 当前载入的内容
 public Uri CurrentSource { get; } // 当前内容的URI
 public Uri Source { get; set; } // 当前内容的URI,或者将导航到的内容的URI

 // 查找导航服务
 public static NavigationService GetNavigationService(DependencyObject dependencyObject);
}

  当你知道这些内容之后,就能使用GetNavigationService来获取寄宿页面的NavigationWindow的NavigationService引用了:

// HomePage.xaml.cs (codebehind)
public partial class HomePage : Page
{
 void viewHyperlink_Click(object sender, RoutedEventArgs e)
 {
  // 查看订单
  ViewOrderPage page = new ViewOrderPage(GetSelectedOrder());
  NavigationService ns = NavigationService.GetNavigationService(this);
  ns.Navigate(page);
 }
 Order GetSelectedOrder() { ... }
 ...
}

  这就使得页面可以执行导航而无需知道宿主的特定信息了。这种需求是如此的普遍,以至于页面提供了一个特定的辅助属性NavigationService,它提供的功能相同:

// HomePage.xaml.cs (code-behind)
public partial class HomePage : Page
{
 void viewHyperlink_Click(object sender, RoutedEventArgs e)
 {
  // 查看订单
  ViewOrderPage page = new ViewOrderPage(GetSelectedOrder());
  this.NavigationService.Navigate(page);
 }

 Order GetSelectedOrder () { ... }
 ...
}

  图9演示了NavigationWindow、NavigationService和页面(Page)之间的关系。你可以看到,NavigationWindow重新实现了自己的NavigationService的Content属性。NavigationWindow不但用这种方法实现了NavigationService的大多数成员,甚至于还增加了一些。例如,你可以通过BackStack和ForwardStack属性,枚举"向前"和"向后"导航历史的内容。


图9:关系

  不幸的是,你无法建立自定义的、聚合了NavigationService的类型(尽管它是一个公共类型,但是它有内部的构造函数,从而阻止了实例化)。作为代替,你必须依赖三种NavigationService聚合器(aggregator)来寄宿内容。这就是我们所知道的导航器(navigator),包括NavigationWindow、Frame和浏览器(仅包括用于Windows Presentation Foundation 1.0的Internet Explorer 6 和 7)。当编写代码让页面使用自己的NavigationService属性的时候,它就可以寄宿在上面的三种导航器中,而不需要做任何更改,如图10所示。


图10:用代码导航

  也许最令人兴奋的是,你发现寄宿在独立应用程序中的一个页面突然就可以寄宿在任何使用Internet Explorer的地方了。
    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章