locked
Windows Phone 7 开发话题讨论(十一) Windows Phone 导航:基本信息 RRS feed

  • 常规讨论

  • Windows Phone 导航:基本信息

    link:

    http://msdn.microsoft.com/en-us/magazine/gg650662.aspx

    http://msdn.microsoft.com/zh-cn/magazine/gg650662.aspx

    Yochay Kiriaty Jaime Rodriguez

    下载代码示例

    Silverlight Windows Phone 应用程序具有一个类似于 Web 的页面模型,最终用户通过该模型从一个页面导航到另一个页面。使用该模型中的专用硬件“后退”按钮,可轻松导航回前面的页面(无需占用屏幕空间),而导航的日记功能(或历史记录)则与平台集成在一起,可简化在不同应用程序之间的导航或转换。本文分为两部分,将为您:

    • 介绍 Windows Phone 上的页面导航模型。
    • 提供要充分利用当前 API 所需的最佳做法,例如,与硬件“后退”按钮进行集成、优化页面加载和卸载,以及确保导航模型满足 Windows Phone 认证准则。
    • 介绍可行且易于遵循的方法,以创建使用当前 API 未能实现的最复杂的导航,包括瞬态内容和页面转换。

    Cedar
    2011年5月16日 4:06

全部回复

  • Windows Phone 导航模型

    Windows Phone 导航模型包含一个框架 (PhoneApplicationFrame) 和一个或多个存放加载到框架中的内容的页面 (PhoneApplicationPage)。

    PhoneApplicationFrame 公开大多数导航事件,并公开您在页面间进行导航时将要使用的 Navigate 方法。此外,它还为应用程序确定客户端区域,并为应用程序栏和系统托盘保留空间。

    PhoneApplicationPage 在用户导航到某一页面时以及通过导航离开某一页面时提供特定于页面的通知。它还处理与硬件“后退”按钮相关的事件。

    PhoneApplicationFrame 和 PhoneApplicationPage 共享一个 NavigationService;实际上,导航操作是由此服务来执行的。Windows Phone 支持日记功能(跟踪您已加载的页面的历史记录,以便您可以返回前面的页面),并公开 API,以便您可以返回。手机不支持前进导航。

    Windows Phone 有三个专用硬件按钮:“后退”、“开始”和“搜索”。对于处理硬件“后退”按钮,有特定的应用程序认证要求:

    • 应用程序不应该阻止用户返回前一页面。只有一种例外,那就是提示发生了数据丢失。此时,您可以提示用户进行确认,并且如果用户选择导航回去的话,您可以允许用户通过。
    • 如果弹出框(软件输入面板,简称 SIP)或其他临时对话框打开,按硬件“后退”按钮可关闭此对话框,但不会离开当前页面(有效地取消“后退”按钮导航)。
    • 在应用程序的第一个屏幕中按“后退”按钮就会退出该应用程序。此功能是免费的。如果您不阻止导航,那么框架就会使您退出 — 实际上,这是退出 Silverlight 应用程序的唯一方法。公开的 API 中没有任何 Exit 方法。
    • 为了使各个应用程序提供一致的用户体验 (UX),应该仅为向后导航使用“后退”按钮。

    “后退”按钮在导航中扮演着一个关键的角色,除此之外,“开始”按钮也参与导航。当用户按“开始”按钮时,便会停用正在运行的应用程序,而当您向前导航到“开始”菜单时,将执行上下文切换。用户此时可以启动另一个应用程序,并在新应用程序中进行导航,或者也可以选择(使用硬件“后退”按钮)导航回之前运行的应用程序。这有效地创建了导航模型,在该导航模型中,“后退”按钮在正在运行的应用程序的页面中进行导航,或在之前运行的应用程序的堆栈中进行导航。


    Cedar
    2011年5月16日 4:08
  • Windows Phone API

    正如之前所提到的,导航的核心角色是 PhoneApplicationFrame 和 PhoneApplicationPage。

    PhoneApplicationFrame 充当应用程序的 RootVisual。启动时,在 App.xaml.cs 中的 App 类中对 PhoneApplicationFrame 进行实例化(请参见图 1)。

    图 1 App.xaml.cs 中实例化 RootFrame 的过程

    1. private void InitializePhoneApplication()
    2. {
    3. if (phoneApplicationInitialized)
    4. return;
    5. // Create the frame but don't set it as RootVisual yet; this allows the splash
    6. // screen to remain active until the application is ready to render.
    7. RootFrame = new PhoneApplicationFrame();
    8. RootFrame.Navigated += CompleteInitializePhoneApplication;
    9. // Handle navigation failures
    10. RootFrame.NavigationFailed += RootFrame_NavigationFailed;
    11. // Ensure we don't initialize again
    12. phoneApplicationInitialized = true;
    13. }

    运行时自动导航到 PhoneApplicationPage 的实例,这是由 WMAppManifest.xml 应用程序清单上的 DefaultTask 中的 NavigationPage 属性指定的,如下所示:

    
       <Tasks>
     <DefaultTask Name ="_default" NavigationPage="MainPage.xaml"/> 
    </Tasks>
      

    让我们详细了解一下职责和 API,PhoneApplicationFrame 公开本文所需的大多数导航方法和事件。图 2 列出了 PhoneApplicationFrame 中最相关的方法、属性和事件。

    图 2 PhoneApplicationFrame 方法、属性和事件

    “名称” 类型 说明
    Navigate Method 导航到由 URI 参数指定的新 PhoneApplicationPage。此参数是一个 Uri,因此,Navigate 调用可有效地对新页面进行实例化并导航到该页面(您不会向其传递一个已经进行过实例化的页面)。
    CanGoBack 只读属性 如果应用程序的 Back 堆栈(日记历史记录)不为空,则返回 true。这意味着用户在应用程序中至少已经向前导航过一次。如果应用程序位于在其中加载的第一个页面,则 CanGoBack 将返回 false,而您将无法以编程方式调用 GoBack,但是,最终用户仍然可以按硬件“后退”按钮,而应用程序将会退出,因为应用程序要返回之前运行的应用程序。
    CanGoForward 只读属性 不适用于 Windows Phone。它始终是 false,因为不支持向前导航。
    UriMapper 特性 获取/设置 UriMapper。虽然超出了本文的范围,但是值得一提的是 Uri 映射受支持。
    GoBack Method 导航到 Back 堆栈中的最新条目。如果 Back 堆栈中没有任何条目,则此方法将引发异常;在调用此方法前,始终都要检查 CanGoForward。
    GoForward Method 在 Windows Phone 上不受支持;将引发 InvalidOperationException
    Navigating 事件 请求新导航时发生。此时,仍可通过在 NavigatingCancelEventArgs 参数中将 Cancel 属性设置为 true 来取消该事件。稍后请查看关于为何不应该在此事件中取消后退导航的说明。
    Navigated 事件 已执行了导航时发生。这并不意味着已经加载了导航到的页面内容。只要找到了内容并导航到内容时便会发生该事件。
    NavigationFailed 事件 当出现错误时发生。
    NavigationStopped 事件 当通过调用 StopLoading 方法停止导航时发生,或者当某一导航正在进行就请求新的导航时发生(第二种情况更常见)。

    上面列出的大多数方法都继承自 Frame,因此,对于熟悉 Silverlight Frame 类的人来说,这些方法看起来应该是比较熟悉的。图 2 中的列表并未列出所有 PhoneApplicationFrame 功能,只列出了与导航相关的功能。

    代码演练:要想了解所有这些事件和属性在操作中的情况,请查看本文附带的示例代码中的 AllNavigationsEvents.xaml.cs。您也可以在图 3中看到事件的触发顺序。

    图 3 在页面间导航时事件的顺序

    此外,PhoneApplicationFrame 还确定应用程序将会获得的客户端区域,并为应用程序栏和系统托盘保留空间。当我们在具有应用程序栏的页面间导航时,这些详细信息很有用,这是因为应用程序栏是在页面级别指定的;有一个系统范围的动画会在加载页面时显示和隐藏应用程序栏。

    导航中的第二个参与者是 PhoneApplicationPage。它在导航中扮演两个关键角色:

    • 处理按下硬件“后退”按钮的操作。
    • 为页面生命周期提供事件以了解何时激活/停用页面。

    为了与硬件“后退”按钮进行集成,PhoneApplicationPage 公开 BackKeyPress 事件。此外,您还可以在页面实例中覆盖页面的虚拟 OnBackKeyPress 方法,以便处理甚至取消“后退”按钮事件。

    PhoneApplicationFrame 具有一个 Navigating 事件和一个 OnNavigatingFrom 通知/回调。在这两种方法中,您可以通过在传递给这些方法的 NavigationCancelEventArgs 参数中设置 e.Cancel = true 来在应用程序中取消导航到其他页面的操作;由于平台上的已知缺陷,您不应该从这些事件/方法中取消“后退”按钮导航。如果您确实在此事件中取消了硬件“后退”按钮,则会中断您的导航,并且需要重新启动应用程序。对于取消硬件“后退”按钮,只推荐两种方法:PhoneApplicationPage BackKeyPress 事件和 OnBackKeyPress 回调。

    请参见图 4 查看可以在其中取消导航的事件和方法的列表,以及关于在相应方法中是否能够取消“后退”按钮的建议和关于如何检查相应事件是否属于后退导航的建议。

    图 4 能够在其中取消导航的事件和方法

    所有者: 事件/通知 能否取消新导航 能否取消后退导航 检查是否属于后退导航
    PhoneApplicationFrame Navigating 不能 能;检查 e.NavigationMode != NavigationMode.Back
    PhoneApplicationPage OnNavigatingFrom 不能 能;检查 e.NavigationMode != NavigationMode.Back
    PhoneApplicationPage OnBackKeyPress 不能(仅在调用“后退”按键时调用) 不需要;仅针对硬件“后退”按键调用
    PhoneApplicationPage BackKeyPress(事件) 不能(仅在调用“后退”按键时调用) 不需要;仅针对硬件“后退”按键调用

    PhoneApplicationPage 对这些事件起补充作用,以便通过针对页面的、更有用的 OnNavigatedTo 和 OnNavigatedFrom 方法回调完成导航生命周期。为了更好地理解并轻松记住何时调用这些回调,最好在它们的方法名称中加上“this page”(意为“此页面”)。当用户已“导航到此页面”时将调用一个方法,然后,当用户“从此页面导航”到另一个页面时将调用另一种方法。

    图 3 显示了您在页面间进行导航时的事件顺序。NavigatedTo 和 NavigatedFrom 之间的对称性使这两种方法成为开始和停止工作(当页面可见时需要,但当页面位于 Back 堆栈中时不需要)的理想之选。另请注意,NavigatedTo 始终都在加载页面之前触发,因此,不要认为此时会加载页面内容。

    OnNavigatedTo 和 OnNavigatedFrom 之所以对 Windows Phone 很重要是因为 Back 堆栈。操作系统为您可以返回的页面保留 Back 堆栈,因此,当您从一个页面导航到另一个页面时,不会立即卸载、销毁页面或对页面进行垃圾回收,而是将页面移动到了 Back 堆栈,并使其(在内存中)保持活动状态,当用户单击“后退”以返回相应页面时,就会直接将该页面添加回可视化树中,而不是重新创建该页面(除非应用程序已被停用,并且在用户离开该页面和单击“后退”这两项操作发生之间已被逻辑删除)。由于向前日记功能不受支持,因此,当您从某个页面导航回前一页面时,可以对页面进行垃圾回收 — 前提是没有对该页面进行其他引用。

    图 5 显示了说明 PhoneApplicationPage 生命周期的图表。

    图 5 PhoneApplicationPage 生命周期

    当您从 Page1 导航到 Page2 再到 Page3 时,在您从相应页面调用 GoBack 方法之前不会对这些页面进行垃圾回收。非活动页面位于 Back 堆栈中,但仍然在内存中。如果这些页面正在侦听全局事件,则事件侦听器仍处于活动状态。

    当您从某个页面进行导航时,虽然没有对该页面进行垃圾回收,但该页面在您导航回该页面之前不再可见或不再处于活动状态,因此,您应该确保,当用户已经通过导航离开某个页面后,再进行清除并释放任何宝贵的资源。例如,如果您正在使用 GeoCoordinateWatcher 侦听位置更改,则您应该在 OnNavigatedFrom 上停止侦听器,并且在用户导航回您的页面且您的 OnNavigatedTo 页面得到调用时重新启动侦听器。

    代码演练:要了解如何在页面位于 Back 堆栈中时将它们保留在内存中,请查看附带的代码下载部分中包含的 GarbageCollectedSample 页面。内存中的页面数量在不断变化,您可以看到,当您向前导航时,页面数量会有所增加,而当您从某个页面导航回去时,页面数量会有所减少。


    Cedar
    2011年5月16日 4:08