原教程地址:http://msdn.microsoft.com/zh-cn/library/windows/apps/xaml/hh986968.aspx
完整项目源码下载:http://download.csdn.net/detail/wxg694175346/5171203
在你返回到代码之前,我们来讨论一下应用的生命周期。激活标志着应用生命周期的开始。在给定的任一时间点,应用处于未运行、正在运行或被挂起的状态。
应用会在用户离开它或 Windows 进入电量不足状态时挂起。 当应用挂起时,它继续驻留在内存中,以便用户可以在挂起应用之间快速且可靠切换,从而恢复运行这些应用。当应用挂起然后恢复运行时,你无须编写任何其他代码就可使其看上去一直在运行中。
但是,Windows 也可以随时终止挂起的应用来为其他应用释放内存或节省电量。如果应用被终止,它会停止运行并且从内存中卸载。
当用户通过按 Alt+F4 或使用关闭手势关闭应用时,应用将被挂起 10 秒钟然后被终止。
Windows 会在挂起应用时通知应用,但不会在终止应用时提供其他通知。 这表示应用必须处理挂起的事件并使用该事件保存其状态,并立即释放其独占资源和文件句柄。
为了创建良好的用户体验,你希望应用看起来从未停止运行。应用需要保留用户输入的任何数据及其更改的设置等等。这表示当挂起应用时需要保存应用的状态,以防 Windows 终止该应用,以便之后可以还原其状态。
在应用中管理的两种数据为:应用数据和会话数据。
在接下来的步骤中,你将了解如何更新应用以保存这些类型的数据。你需要保存什么状态?目前,用户可更改的唯一内容是其名称条目。用户还可以单击 Say "Hello" 按钮来生成个性化问候。
在部分 1:创建“Hello, world”应用中,你用一个基于“基本页面”模板的文件替换了默认的 MainPage 文件。当使用“基本页面”模板时,Microsoft Visual Studio 向 Common 文件夹中的项目添加多个文件。这些文件之一包含 SuspensionManager
类。SuspensionManager
为帮助程序类,可简化应用的生命周期管理。该类可为你实现很多操作。它会保存和还原托管应用页面的 Frame 的导航状态。在单页应用中,保存导航状态似乎不是非常重要,但在向应用中添加多个页面时该操作就变得非常重要了。它还为每个页面提供了保存并还原其状态的机会。SuspensionManager
序列化页面状态数据并将其写入应用的本地存储中的 XML 文件。
若要使用应用中的 SuspensionManager
类,首先需要注册主屏 Frame。完成后,SuspensionManager
会了解有关应用中每页的信息,并且它可以保存和还原导航状态。在 App.xaml.cs/vb 的 OnLaunched 方法中创建 Frame 之后,立即进行注册。
使用 SuspensionManager 的步骤
SuspensionManager.RegisterFrame
方法以注册根 Frame。
HelloWorld.Common.SuspensionManager.RegisterFrame(rootFrame, "appFrame");
创建新的 Frame 之后添加如下代码。
if (rootFrame == null) { // Create a Frame to act as the navigation context and navigate to the first page rootFrame = new Frame(); HelloWorld.Common.SuspensionManager.RegisterFrame(rootFrame, "appFrame"); ...
通常,在应用中管理的两种数据为:应用数据和会话数据。应用数据保留在会话中且用户必须始终可以访问这些数据。在应用中,nameInput
TextBox 的 Text 为应用数据。在应用的整个生命周期内始终不断保存重要的应用数据。由于应用最多只有 5 秒钟来运行挂起事件处理程序中的代码,因此你需要确保当应用挂起时将重要应用数据保存到永久性存储中。
Windows 提供了 Windows.Storage.ApplicationData 对象,可帮助你管理应用数据。 此对象的 RoamingSettings 属性会返回 ApplicationDataContainer。你可以使用此 ApplicationDataContainer 来存储会话中保留的应用数据。当用户键入用户名时,我们在漫游 ApplicationDataContainer 中存储该名称。
注意 本教程介绍如何使用 RoamingSettings。漫游设置应用数据容器实现了一种简单的数据存储方法,用户可以跨多个计算机使用该方法。基本上,该方法会在后台为你将数据上载到云中。你也可以使用本地设置应用数据容器 (LocalSettings),但只应在要存储计算机特定信息时使用它。
在应用程序中尽可能频繁地保存永久性应用数据。此时,你处理 TextBox.TextChanged 事件并当用户输入用户名时保存该用户名。
保存应用数据的步骤
nameInput
TextBox。roamingSettings
中的 nameInput
文本。
Windows.Storage.ApplicationDataContainer roamingSettings =
Windows.Storage.ApplicationData.Current.RoamingSettings;
roamingSettings.Values["userName"] = nameInput.Text;
会话数据为临时数据,它与应用中用户的当前会话相关。会话会在以下情形下结束:用户使用关闭手势或 Alt + F4 关闭应用、重新启动计算机或注销计算机。 在应用中,greetingOutput
TextBlock 的 Text 为会话数据。仅当 Windows 挂起和终止应用时才还原该数据。需要保存应用 Frame 的导航状态,以便应用可以还原到之前运行时的同一页面,并告知SuspensionManager
还原哪个页面的状态。还需要保存页面自身的状态。此为保存 greetingOutput
文本的位置。使用SuspensionManager
类来保存 Application.Suspending 事件处理程序中的会话状态。
(有关保存状态的其他方法的详细信息,请参阅管理应用数据和有效使用状态。)
App.xaml.cs/vb 文件包含 Application.Suspending 事件的处理程序。Windows 即将挂起应用时会调用此事件处理程序。 这是保存应用状态以防该应用被终止的时机。使用 SuspensionManager
类来简化会话状态保存过程。该类会保存应用的导航状态并为你提供保存活动页面会话状态的机会。
保存会话状态的步骤
OnSuspending
方法签名添加 async 关键字。 有关异步编程的详细信息,请参阅快速入门:使用 await 运算符进行异步编程。
OnSuspending
方法中,调用 SuspensionManager.SaveAsync
方法。
await HelloWorld.Common.SuspensionManager.SaveAsync();
调用 SaveAsync
时可保存 Frame 的导航状态,从而为 Page 提供保存其内容的机会。
下面是执行更新的完整 OnSuspending
方法。
/// <summary> /// Invoked when application execution is being suspended. Application state is saved /// without knowing whether the application will be terminated or resumed with the contents /// of memory still intact. /// </summary> /// <param name="sender">The source of the suspend request.</param> /// <param name="e">Details about the suspend request.</param> private async void OnSuspending(object sender, SuspendingEventArgs e) { var deferral = e.SuspendingOperation.GetDeferral(); //TODO: Save application state and stop any background activity await HelloWorld.Common.SuspensionManager.SaveAsync(); deferral.Complete(); }
SaveState
方法添加此代码以保存页面状态。
pageState["greetingOutputText"] = greetingOutput.Text;
SuspensionManager
类会序列化 pageState
字典并将其保存到 XML 文件。在 pageState
中保存的数据仅为此会话保存。此处保存 greetingOutput
文本。
以下是 SaveState
方法的完整代码。
/// <summary> /// Preserves state associated with this page in case the application is suspended or the /// page is discarded from the navigation cache. Values must conform to the serialization /// requirements of <see cref="SuspensionManager.SessionState"/>. /// </summary> /// <param name="pageState">An empty dictionary to be populated with serializable state.</param> protected override void SaveState(Dictionary<String, Object> pageState) { pageState["greetingOutputText"] = greetingOutput.Text; // The user name is already saved, so you don't need to save it here. }
这就是在应用被终止前保存应用状态所需执行的全部操作。现在需要了解如何在下次用户启动应用时还原应用状态。
之前,你看到 App.xaml.cs/vb 文件包含用于处理应用激活的代码。有多种不同的方法来激活应用。现在,我们来了解Launch 激活和 OnLaunched 方法。
只要应用未运行,该应用就会被启动,然后用户激活该应用。当应用启动时,Windows 显示应用的一个初始屏幕。
我们来了解用于处理应用激活的 App.xaml.cs/vb 中的代码。该代码定义了 OnLaunched 方法的替代。 仅当激活为Launch 激活时才执行此方法中的代码。(你可以替代其他方法来处理其他种类的激活,但此处我们不这样做。有关详细信息,请参阅应用程序生命周期。)
首先,该代码声明了一个 Frame,并尝试向其分配当前窗口内容。
Frame rootFrame = Window.Current.Content as Frame;
如果窗口已包含一个 Frame,它表示应用已初始化,因此会跳过该 Frame 的初始化。
如果应用未初始化,则代码会创建 Frame 来托管应用页面。向 SuspensionManager
注册 Frame。此为在步骤 1 中添加的代码。
接下来,代码会检查之前的执行状态以查看上次应用如何关闭。如果之前的执行状态为 Terminated,则表示应用上次运行时,Windows 成功挂起而后终止了该应用。在这种情形下,需要还原应用状态。
// Do not repeat app initialization when the Window already has content, // just ensure that the window is active if (rootFrame == null) { // Create a Frame to act as the navigation context and navigate to the first page rootFrame = new Frame(); HelloWorld.Common.SuspensionManager.RegisterFrame(rootFrame, "appFrame"); if (args.PreviousExecutionState == ApplicationExecutionState.Terminated) { //TODO: Load state from previously suspended application } // Place the frame in the current Window Window.Current.Content = rootFrame; }
接下来,代码会检查 Frame 是否包含任何内容。如果应用正在运行,或者导航状态已还原,则该 Frame 已具有内容。否则,Frame 会导航到应用的首页。在本例中,它会导航到 MainPage。
if (rootFrame.Content == null) { // When the navigation stack isn't restored navigate to the first page, // configuring the new page by passing required information as a navigation // parameter if (!rootFrame.Navigate(typeof(MainPage), args.Arguments)) { throw new Exception("Failed to create initial page"); } }
最后,代码将激活窗口。
// Ensure the current window is active
Window.Current.Activate();
既然你了解启动应用时发生的情况,我们来看看如何还原应用状态。
还原应用状态的步骤
OnLaunched
方法签名添加 async 关键字。
protected async override void OnLaunched(LaunchActivatedEventArgs args)
SuspensionManager.RestoreAsync
方法。 调用 RestoreAsync
时会还原 Frame 的导航状态,从而为 Page 提供还原其内容的机会。
if (args.PreviousExecutionState == ApplicationExecutionState.Terminated) { //TODO: Load state from previously suspended application await HelloWorld.Common.SuspensionManager.RestoreAsync(); }
LoadState
方法添加代码以还原页面状态。
pageState
字典是否存在且是否具有名为 greetingOutputText
的密钥。如果该密钥存在,则使用它还原 greetingOutput
文本。
// Restore values stored in session state. if (pageState != null && pageState.ContainsKey("greetingOutputText")) { greetingOutput.Text = pageState["greetingOutputText"].ToString(); }
// Restore values stored in app data. Windows.Storage.ApplicationDataContainer roamingSettings = Windows.Storage.ApplicationData.Current.RoamingSettings; if (roamingSettings.Values.ContainsKey("userName")) { nameInput.Text = roamingSettings.Values["userName"].ToString(); }
以下是 LoadState
方法的完整代码。
/// <summary> /// Populates the page with content passed during navigation. Any saved state is also /// provided when recreating a page from a prior session. /// </summary> /// <param name="navigationParameter">The parameter value passed to /// <see cref="Frame.Navigate(Type, Object)"/> when this page was initially requested. /// </param> /// <param name="pageState">A dictionary of state preserved by this page during an earlier /// session. This will be null the first time a page is visited.</param> protected override void LoadState(Object navigationParameter, Dictionary<String, Object> pageState) { // Restore values stored in session state. if (pageState != null && pageState.ContainsKey("greetingOutputText")) { greetingOutput.Text = pageState["greetingOutputText"].ToString(); } // Restore values stored in app data. Windows.Storage.ApplicationDataContainer roamingSettings = Windows.Storage.ApplicationData.Current.RoamingSettings; if (roamingSettings.Values.ContainsKey("userName")) { nameInput.Text = roamingSettings.Values["userName"].ToString(); } }
现在你可以构建并运行应用,然后查看如何保存和还原会话状态。到目前为止,你已测试该应用,方法是在调试模式下运行该应用以及在 Visual Studio 中选择“调试”>“停止调试”停止该应用。但是执行此操作会导致应用执行正常关闭且Suspending 事件不会出现。幸运的是,Visual Studio 可让你模拟挂起、终止以及还原某个应用。
在 Visual Studio 中模拟挂起、终止以及还原应用
当调试程序运行时,默认情况下会出现“调试位置”工具栏。如果未看到该工具栏,则单击“视图”>“工具栏”>“调试位置”来显示该工具栏。
Visual Studio 会模拟应用挂起和终止,因此会出现 Suspending 事件且会执行状态管理代码。
现在,用户名被还原,因为用户名在你键入时已进行保存。问候未被还原,因为 Suspending 事件未发生,因此未保存会话状态。
祝贺你完成第二个教程!你已了解如何在 Windows 应用商店应用中保存应用数据和会话状态。