Windows10-开发秘籍-全-

Windows10 开发秘籍(全)

原文:Windows 10 Development Recipes

协议:CC BY-NC-SA 4.0

一、Windows 10 应用入门

Windows 10 是微软在 2015 年 7 月 29 日发布的新操作系统。自 Windows 8.1 以来,人们一直在期待它。对于应用开发者(商店和手机),Windows 8.1 和 Visual Studio 2013 给出了一种独特的编程模型,称为通用 Windows 8 应用。通用 Windows 应用能够从一个共享的代码库同时面向 Windows 和 Windows Phone。Windows 10 超越了 Windows 和 Windows Phone,引入了所谓的通用 Windows 平台(UWP)应用。有了这个新平台,你可以保证在不同的设备上有一个一致的核心 API 层。UWP 开发的单个软件包可以安装在多种设备和设备系列上。设备系列包括桌面操作系统、移动操作系统(手机和平板电脑)、Xbox 和物联网(IoT)设备以及无头设备系列。这意味着您的应用可以在任何设备上运行,包括手机、平板电脑、PC、Xbox 游戏机等。本章介绍 Windows 10 通用 Windows 平台应用开发。

1.1 检查通用 Windows 平台

问题

你决定开发一个面向 PC、手机、平板电脑和 Xbox 的通用 Windows 平台应用。您想要了解通用 Windows 平台—设备系列和通用控件。

解决办法

让我们来看看通用 Windows 平台的一些亮点。

一个 Windows 平台

Windows 10 带来了一个 Windows 平台(见图 1-1 )。在 Windows 10 中,操作系统已经过重构,现在具有跨不同 Windows 10 平台的通用核心。这意味着您拥有一个通用的 Windows 内核、一个文件 I/O 堆栈和一个应用模型。简单来说,通用 Windows 平台就是联系人和版本的集合。对于 Windows Phone 8.1 和 Windows 8.1 应用,您必须面向操作系统—Windows 或 Windows Phone,而对于通用 Windows 平台应用,您面向设备。

A978-1-4842-0719-2_1_Fig1_HTML.jpg

图 1-1。

Universal Windows Platform apps model

UWP 应用可以在各种具有不同外形和输入机制的设备上运行。当您开发 UWP 应用时,您需要确保为每台设备量身定制体验,并利用各自设备的功能。Windows 10 上有一个通用的核心或内核。每个设备都向基础层添加自己的 API。因此,要访问设备的独特 API,您需要编写条件代码来在您的应用中提供设备特定的功能。

设备系列

Windows 和 Windows Phone 是开发人员针对其 Windows 8.1 和 Windows Phone 8 应用的操作系统。但随着 Windows 10 现在在各种设备上可用,UWP 应用针对特定的设备家族。设备系列标识了该系列中设备的 API、特性和行为。它还决定了可以安装应用的设备集。图 1-2 展示了器件系列的层次结构。

A978-1-4842-0719-2_1_Fig2_HTML.jpg

图 1-2。

Universal device family hierarchy

一组 API 有一个名称和一个版本号。这是设备系列操作系统的基础。例如,个人电脑运行桌面操作系统,并基于桌面设备系列。另一方面,手机和平板电脑拥有基于移动设备家族的移动操作系统。我希望您现在对设备系列有一个确切的概念。

通用控件

借助 UWP,应用可以在不同的外形、屏幕分辨率、dpi 和其他设备特性上运行。应用必须适应这些不同的外形和分辨率。Windows 10 提供了新的通用控件、布局和工具,将帮助您根据运行应用的设备来调整应用 API。Windows 10 包括新的控件,如日历和拆分视图。专用于 Windows Phone 应用的 Pivot control 现在可用于通用 Windows 平台应用。

通用输入处理

通过 UWP 应用,通用控件现在支持各种输入,如鼠标、键盘、触摸、笔和控制器(如 Xbox 控制器)。该平台提供了一些核心 API,可以在您的应用中用来处理各种输入。下面是一些可以使用的输入 API。

  • CoreInput:允许您使用原始输入。
  • PointerInput:将原始触摸、鼠标和笔统一到一个一致的界面中。
  • PointerDevice:一个设备 API,允许您查询设备功能以了解可用的输入类型。

1.2 通用 Windows 平台的开发工具

问题

你想开始开发通用的 Windows 平台应用。您想知道应该使用哪些工具进行开发。

解决办法

您需要在开发计算机上安装 Windows 10 操作系统和 Visual Studio 2015 社区版。

要安装 Windows 10,请访问微软 http://windows.microsoft.com/en-us/windows/buy 。如果您已经安装了 Windows 操作系统,您可以免费将操作系统升级到 Windows 10。

要安装 Visual Studio 2015 (VS 2015)社区版,可以访问微软网站 https://www.visualstudio.com/en-us/downloads/visual-studio-2015-downloads-vs 。安装 VS 2015 时,需要确保选择了通用的 Windows app 开发工具(见图 1-3 )。这在可选功能列表中。

A978-1-4842-0719-2_1_Fig3_HTML.jpg

图 1-3。

Visual Studio 2015 Community Edition installation

1.3 创建通用 Windows 平台应用

问题

您想要创建一个简单的通用 Windows 平台应用。

解决办法

Visual Studio 2015 附带预安装的通用 Windows 平台应用项目模板。您将使用该模板创建您的第一个应用。

它是如何工作的

让我们看看如何使用 Visual Studio 2015 创建一个新的通用 Windows 平台应用。

Open Visual Studio 2015 Community edition. Select File ➤ New Project. In the New Project dialog window, select Templates ➤ JavaScript ➤ Windows ➤ Universal from the Installed Templates section. Select Blank App (Universal Windows) from the available project templates (see Figure 1-4). Provide a name and location for the app and click OK.

A978-1-4842-0719-2_1_Fig4_HTML.jpg

图 1-4。

New project template   Visual Studio will prepare the project. Figure 1-5 shows what the new solution looks like.

A978-1-4842-0719-2_1_Fig5_HTML.jpg

图 1-5。

Solution Explorer As part of the project template, you get css, images, js, and WinJS folders. You also have a pre-created default.html page to get started.

  • css文件夹是保存定制样式表(.css文件)的地方。
  • images文件夹包含您想在应用中使用的任何图像。
  • js是 JavaScript 文件夹,用于保存与应用相关的 js 文件。您会看到预先创建的default.js文件,其中包含以下代码。

(function () {         "use strict";         var app = WinJS.Application;         var activation = Windows.ApplicationModel.Activation;         app.onactivated = function (args) {                 if (args.detail.kind === activation.ActivationKind.launch) {                     if (args.detail.previousExecutionState !==                 activation.ApplicationExecutionState.terminated) {                             //App Initilization code                         } else {                                 //Restore app sessions state                         }                         args.setPromise(WinJS.UI.processAll());                 }         };         app.oncheckpoint = function (args) {             //save any app state here         };         app.start(); })();   The code creates a WinJS.Application object instance and starts the application.   Open default.html by double-clicking the file in Solution Explorer. Here is the default code you see in the file: <!DOCTYPE html> <html> <head>     <meta charset="utf-8" />     <title>Ch1R3</title>     <link href="WinJS/css/ui-dark.css" rel="stylesheet" />     <script src="WinJS/js/basejs"></script>     <link href="/css/default.css" rel="stylesheet" />     <script src="/js/default.js"></script> </head> <body class=”win-type-body”>     <p>Content goes here</p> </body> </html>   It’s pretty much empty with just one line of text that reads, “Content goes here.” Replace this text with “Hello World!” This will be our Hello World application with UWP ☺.   Press Ctrl+Shift+B on your keyboard or select Build ➤ Build solution. Visual Studio builds the project.

1.4 运行通用 Windows 平台应用

问题

您已经创建了一个新的 UWP 应用,并希望运行该应用来查看它的运行情况。你想知道怎么做。

解决办法

Visual Studio 2015 提供了许多选项来运行您的 UWP 应用:

  • 在 Windows Phone 10 模拟器上运行应用
  • 在 Windows 10 模拟器上运行应用
  • 在本地机器上运行应用
  • 在设备上运行应用

它是如何工作的

当您安装 Visual Studio 2015 时,它还会安装 Windows Phone 10 模拟器和 Windows 10 模拟器。这些模拟器和仿真器模拟 Windows Phone 和 Windows 中不同的设备和屏幕大小。Visual Studio 2015 允许您选择其中一个选项来部署您的应用。您也可以直接从 Visual Studio 将应用部署到您的计算机上,并将其作为本地应用运行。让我们看一下所有这些选项,一次一个。

在 Windows Phone 10 模拟器上运行应用

在 Visual Studio 中,从目标组合框中选择一个可用的 Windows 10 模拟器。图 1-6 显示了可用仿真器的列表。

A978-1-4842-0719-2_1_Fig6_HTML.jpg

图 1-6。

Windows Phone 10 emulators target

按 F5 在选定的 Windows Phone 10 模拟器上运行应用。图 1-7 显示了 4 英寸 Windows Phone 10 上的截图。

A978-1-4842-0719-2_1_Fig7_HTML.jpg

图 1-7。

UWP app on Windows Phone 10 emulator

在 Windows 10 模拟器上运行应用

在 Visual Studio 中,从目标组合框中选择 Simulator。此选项允许您将应用部署到 Windows 10 模拟器(参见图 1-8 )。

A978-1-4842-0719-2_1_Fig8_HTML.jpg

图 1-8。

Windows 10 simulator target

按 F5 在 Windows 10 模拟器上运行应用。图 1-9 是该应用在模拟器上的截图。

A978-1-4842-0719-2_1_Fig9_HTML.jpg

图 1-9。

UWP app on Windows 10 simulator

在本地机器上运行应用

通常情况下,Windows 10 应用需要从 Windows Store 下载,然后安装在您的机器上。但是这个工作流程只适用于最终用户,不适用于开发人员。在应用开发期间,开发人员可以直接在他们的开发机器上部署和运行他们的应用。

在本地机器上运行应用之前,您需要在机器上启用开发人员模式。

在你的机器上,进入设置➤更新&开发者安全➤,如图 1-10 所示。

Select the Developer mode radio button.   In Visual Studio, select Local Machine from the target combo box, as shown in Figure 1-11.

A978-1-4842-0719-2_1_Fig11_HTML.jpg

图 1-11。

Local Machine target   Press F5 to run the app on your development machine. Figure 1-12 is a screenshot of the app running on a local machine.

A978-1-4842-0719-2_1_Fig12_HTML.jpg

图 1-12。

UWP app on local machine

A978-1-4842-0719-2_1_Fig10_HTML.jpg

图 1-10。

Developer features settings

在设备上运行应用

如果你有 Windows 10 移动设备,你可以直接在上面部署和运行你的 UWP 应用。但是,在您可以将应用直接从 Visual Studio 部署到设备上之前,您需要启用您的手机,以允许在开发期间安装应用。这也被称为下载应用。这种模式被称为开发者模式,它是一种电话设置。在您的 Windows Phone 10 设备上,转到“设置”“➤更新与安全”“面向开发者的➤”。选择开发者模式,如图 1-13 所示。完成此步骤后,您的应用可以从 Visual Studio 直接部署到您的设备上。

A978-1-4842-0719-2_1_Fig13_HTML.jpg

图 1-13。

Developer Mode setting on Windows Phone device

在 Visual Studio 中,选择 Device 作为目标,如图 1-14 所示。

A978-1-4842-0719-2_1_Fig14_HTML.jpg

图 1-14。

Device target

接下来,按 F5 在您的设备上运行应用。输出应该类似于您在模拟器中看到的内容。

二、WinJS 基础知识

使用平台的库构建应用时,了解库提供的功能非常重要。在这一章中,你将看到 WinJS 为使用 JavaScript、HTML 和 CSS 构建 Windows 运行时应用提供的各种特性。这些特性包括名称空间、模块、承诺和查询选择器。几乎所有使用 WinJS 构建的应用都使用这些特性。通过利用名称空间和模块等特性,您可以使您的应用更容易维护,而不是在全局名称空间下添加所有内容。

2.1 JavaScript 中的名称空间

问题

使用 WinJS 库进行开发时,您需要对常见功能进行分组,并防止 JavaScript 代码中的命名冲突。

解决办法

名称空间允许开发人员更好地分组或组织公共功能。其他编程语言——c#、VB.NET、Java 等等——都提供了这个特性。许多 JavaScript 框架不支持名称空间,但是 WinJS 提供了一个特性,开发人员可以在他们的项目中使用名称空间。名称空间可以派上用场,尤其是当您的应用利用由不同开发人员编写的多个库时。

开发人员可以使用WinJS.Namespace.define方法来声明名称空间。

它是如何工作的

WinJS 库允许开发人员通过使用WinJS.Namespace.define方法来声明名称空间。

WinJS.Namespace.define方法有两个参数。

  • Name:这是第一个参数,代表新名称空间的名称。
  • Members:这是第二个参数,完全可选。此参数表示需要添加到正在定义的命名空间的对象列表。

以下是使用 WinJS 在 Windows 应用商店通用应用中创建新命名空间的步骤。

Launch Visual Studio 2015 and select File ➤ New Project. In the New Project dialog, select JavaScript ➤ Windows ➤ Universal from the Installed Templates sidebar. Select Blank App (Universal Windows) from the template and name the project ch2.1WinJSFundamentals. Click the OK button. This created the necessary files within the Visual Studio solution.   Add a new JavaScript file in the ch2.1WinJSFundamentals project by right-clicking the project’s js folder and selecting the Add ➤ New Item option. Select the JavaScript file from the Add New Item dialog and name the file WinJSFundamentals.js. Add the following code to the file.

// Define the Namespace Developerpublish

WinJS.Namespace.define("DeveloperPublish");

// Utilities created in the DeveloperPublish Namespace

DeveloperPublish.Utilities = {

DisplayMessage: function () {

return "Message from DeveloperPublish Namespace";

}

};

// Define the Namespace Apress and create the Utilities under it.

WinJS.Namespace.define("Apress",

{

Utilities: {

DisplayMessage: function () {

return "Message from Apress Namespace";

}

}

});

console.log(DeveloperPublish.Utilities.DisplayMessage());

console.log(Apress.Utilities.DisplayMessage());

在前面的代码片段中,DeveloperPublish名称空间演示了带有单个参数的WinJS.Namespace.define方法的用法。对象被添加到命名空间中,命名空间后跟一个句点和对象的名称。

Apress 命名空间是用两个参数创建的。第一个参数是名称空间的名称 Apress 而第二个参数是作为 Apress 名称空间一部分的对象。

Open the default.html page and add the reference to the WinJSFundamentals.js file by using the following code snippet: <script src="js/WinJSFundamentals.js"></script>   Run the Windows app. You will notice that the string that is returned from DisplayMessage of the Utilities class is displayed in the console window, as shown in Figure 2-1.

A978-1-4842-0719-2_2_Fig1_HTML.jpg

图 2-1。

Display the string in the Visual Studio 2015 console window

WinJS.Namespace是默认的名称空间,它提供如下功能

  • promise物体
  • 定义名称空间、logxhr的函数。

以下是属于 WinJS.Namespace 的对象和函数

  • 这个对象提供了在 JavaScript 代码中实现异步编程的机制。
  • validation:可以设置该属性来显示验证的结果。
  • define:这个函数用指定的名字定义一个新的名称空间。
  • defineWithParent:该函数在指定的父命名空间下定义一个具有指定名称的命名空间。
  • log:该函数将输出写入 Visual Studio 2015 中的 JavaScript 控制台窗口。
  • xhr:这个函数将对 XMLHttpRequest 的调用包装在一个承诺中。

请注意,您不应该在定义名称空间之前引用它。当您试图在命名空间定义之前访问它时,会收到“命名空间未定义”错误。

WinJS 库中包含了命名空间功能,以便更好地处理与作用域相关的问题。WinJS 中名称空间实现的源代码可以在项目的WinJS/js文件夹下的base.js文件中找到。

2.2 向现有名称空间添加名称空间

问题

您需要向现有的名称空间添加一个名称空间,并定义您的功能。

解决办法

使用WinJS.Namespace.defineWithParent方法将名称空间添加到 WinJS 中的现有名称空间。

它是如何工作的

WinJS.Namespace.defineWithParent方法允许开发人员向现有名称空间添加新的名称空间。这类似于define方法;它允许您在现有名称空间下创建一个新的名称空间。

WinJS.Namespace.defineWithParent方法接受三个参数:

  • 父名称空间:第一个参数是父名称空间的名称。
  • Name:这是要添加到父名称空间的名称空间的名称。
  • Members:要添加到新命名空间的对象列表。这是一个可选参数。

让我们使用配方 2.1 中创建的配方。打开项目中的WinJSFundamentals.js文件,并用下面的代码片段替换它。

WinJS.Namespace.define("Apress");

WinJS.Namespace.defineWithParent(Apress, "Books" ,

{

Utilities :

{

DisplayMessage: function () {

return "Message from Apress.Books Namespace";

}

}

}

);

console.log(Apress.Books.Utilities.DisplayMessage());

运行 Windows Store 项目,您应该会看到字符串“Message from Apress。Books Namespace "显示在 Visual Studio JavaScript 控制台窗口中,如图 2-2 所示。

A978-1-4842-0719-2_2_Fig2_HTML.jpg

图 2-2。

Display the string in the JavaScript console window in Visual Studio 2015

请注意,名称空间应该只包含类、函数、常数和其他名称空间。

2.3 在 WinJS 中创建类

问题

您需要在 Windows 运行时应用中用 JavaScript 代码创建一个类。

解决办法

使用WinJS.Class.define方法在 WinJS 中创建一个类。

它是如何工作的

C#和 VB.NET 是面向对象的语言。它们对语言中面向对象的概念有很好的实现和支持;其中一个功能是创建类。另一方面,JavaScript 没有创建类的内置支持。JavaScript 中的一切都被视为对象。

WinJS 允许开发人员创建类并在他们的应用中使用它们。

您可以使用WinJS.Class.define方法在 WinJS 中创建新类。

WinJS.Class.define方法有三个参数。

  • 构造函数:第一个参数让开发人员初始化一个新对象。
  • 实例成员:第二个参数是实例成员的集合,包括属性和方法。
  • 静态成员:第三个参数包括静态属性和静态方法。

打开项目中的WinJSFundamentals.js文件,并用下面的代码片段替换它。

// Create a class called Author

var Author = WinJS.Class.define(

function (name, title) {

this.name = name;

this.title = title;

},

{

_Name: undefined,

_title: undefined,

name : {

set :function(value)

{

this._Name = value;

},

get :function()

{

return this._Name;

}

},

title : {

set :function(value)

{

this._title = value;

},

get :function()

{

return this._title;

}

}

});

// instantiate the author class by invoking the constructor with 2 parameters

var author1 = new Author("Senthil", "WinJS recipes");

// display the name and the title  in the console window.

console.log(author1.name);

console.log(author1.title);

在前面的代码片段中,Author类是使用WinJS.Class.define方法创建的。该方法的第一个参数是构造函数,它接受两个参数并初始化名称和标题。

Author类有两个属性。

  • 标题与其backing field _title
  • 名称与其backing field _name

这两个属性都包含一个 getter 方法和一个 setter 方法。例如,看看下面的属性。

title : {

set :function(value)

{

this._title = value;

},

get :function()

{

return this._title;

}

}

title属性有一个set方法,它允许开发人员为该属性设置一个值。类似地,您可以使用带有get方法的title属性来检索_title的值。从开发人员的角度来看,调用<PropertyName>对象足以获取或设置值。

运行 Windows 项目。您应该看到实例化对象时使用的名称和标题,如图 2-3 所示。

A978-1-4842-0719-2_2_Fig3_HTML.jpg

图 2-3。

Displaying the name and title in the JavaScript console window in Visual Studio 2015

温家。类命名空间为定义类提供了以下帮助函数。

  • define:这个函数使用指定的构造函数和实例成员定义一个类。
  • derive:这个函数使用原型继承为指定的类创建一个子类。
  • mix:这个函数使用指定的构造函数定义一个类,并组合所有 mixin 对象指定的实例成员集合。

2.4 在 WinJS 中派生类

问题

您需要在 WinJS 应用中应用继承概念。

解决办法

在 WinJS 中使用WinJS.Class.derive方法从一个类派生另一个类。

它是如何工作的

WinJS 库提供了WinJS.Class.derive方法,允许开发人员应用继承来从一个类派生另一个类。WinJS.Class.derive方法采用以下参数。

  • 基类:当前类需要继承的类。
  • 构造函数:这个参数指的是可以用来初始化类成员的constructor函数。
  • 实例成员:该参数定义实例成员,包括属性和方法。
  • 静态成员:该参数定义静态属性和静态方法。

打开WinJSFundamentals.js文件,用下面的代码片段替换代码。

// Create a class called Employee

var Employee = WinJS.Class.define(

function () {

this.name = name;

this.type = "Employee";

},

{

_Name: undefined,

_type: undefined,

name : {

set :function(value)

{

this._Name = value;

},

get :function()

{

return this._Name;

}

},

type: {

set :function(value)

{

this._type = value;

},

get :function()

{

return this._type;

}

}

});

var ContractEmployee = WinJS.Class.derive(Employee,

function (name) {

this.name = name;

this.type = "Contract Employee";

});

var ContractEmployee1 = new ContractEmployee("Senthil");

// display the name and the title  in the console window.

console.log(ContractEmployee1.name);

console.log(ContractEmployee1.type);

这段代码片段创建了一个名为Employee的类。后来,创建了另一个名为ContractEmployee的类;它来自于Employee类。创建了一个契约雇员实例,其姓名和雇佣类型显示在控制台窗口中。

从 Visual Studio 运行 Windows 应用商店项目。这将在 JavaScript 控制台窗口中显示名称和类型,如图 2-4 所示。

A978-1-4842-0719-2_2_Fig4_HTML.jpg

图 2-4。

Displaying the name and type of employment in the JavaScript console window in Visual Studio 2015

WinJS.Class.derive函数的行为类似于WinJS.Class.define函数,除了它使用基类的原型使用Object.create函数来构造派生类。Object.create方法通过原型化父对象从一种类型派生出另一种类型;它还添加属于子对象的属性。

2.5 在 WinJS 中创建 Mixins

问题

您需要组合来自多个 JavaScript 对象的方法和属性,而不使用WinJS.Class.derive方法。

解决办法

使用WinJS.Class.mix方法组合 WinJS 中多个 JavaScript 对象的方法和属性。

它是如何工作的

WinJS.Class.derive方法使用原型继承,各有利弊。它需要额外的处理时间,并且会影响性能。这可以通过使用WinJS.Class.mix方法来克服。

WinJS.Class.mix方法有两个参数。

  • 构造函数:第一个参数,用于初始化类成员。
  • Mixin:第二个参数是接受 mixin 方法的数组

打开项目中的WinJSFundamentals.js文件,并用下面的代码片段替换它。

// Create a class called Employee

var Employee = WinJS.Class.define(

function () {

this.name = name;

this.type = "Employee";

},

{

_Name: undefined,

_type: undefined,

name : {

set :function(value)

{

this._Name = value;

},

get :function()

{

return this._Name;

}

},

type: {

set :function(value)

{

this._type = value;

},

get :function()

{

return this._type;

}

}

});

var ContractEmployee = WinJS.Class.mix(

function (name) {

this.name = name;

this.type = "Contract Employee";

},Employee);

var ContractEmployee1 = new ContractEmployee("Senthil");

// display the name and the title  in the console window.

console.log(ContractEmployee1.name);

console.log(ContractEmployee1.type);

在这个代码示例中,创建了一个Employee类,然后创建了另一个名为ContractEmployee的类;它继承自Employee类。请注意,您使用了mix方法,而不是derive方法。

嗯,代码可能看起来与使用derive方法的代码相似,但是 mixin 增加了更多的特性。其中一个特性是支持多重继承。由于mixin方法中的第二个参数是一个 mixins 数组,您可以让ContractEmployee类实现多个类的特性。

当您执行这个程序时,您会看到员工的姓名和类型,如图 2-5 所示。

A978-1-4842-0719-2_2_Fig5_HTML.jpg

图 2-5。

Displaying the name and employee type in the JavaScript console window in Visual Studio 2015

Mixins 可以用来给你的类型增加功能。Mixins 通常包含可以添加到 WinJS 中许多类型的实现函数。

在 WinJS 中,您可以使用以下 mixins 之一来管理事件和绑定。

  • 这个 mixin 可以用来给你定义的任何类型添加事件管理功能。它包括像WinJS.Utilities.eventMixin.addEventListenerWinJS.Utilities.eventMixin.removeEventListenerWinJS.Utilities.eventMixin.dispatchEvent这样的函数来引发和处理您定义的自定义事件。
  • WinJS.Binding.dynamicObservableMixin:该函数用于添加绑定管理功能,开发者可以将自定义对象绑定到一个控件上,该控件能够在属性值发生变化时通知监听器。

2.6 WinJS 中的封装

问题

您希望构建一个库,并且希望只向外部访问公开其中的一些方法。您需要支持 WinJS 应用中的封装。

解决办法

使用函数和名称空间的功能来实现这一点。变量可以有全局作用域或函数作用域。这个特性可以用来在 JavaScript 中引入封装功能。

它是如何工作的

当您创建自己的 JavaScript 库时,您可能希望同时创建公共和私有方法。公共方法可以作为 API 公开,并且可以由第三方开发人员使用。

这里的问题是 JavaScript 不支持访问修饰符。JavaScript 中的变量有以下范围。

  • 全局范围:这在整个应用中都是可用的。
  • 函数作用域:这仅在函数内部可用。

WinJS 中使用了函数作用域特性来隐藏方法,使其具有一定的私有性。通过手动将方法添加到命名空间,可以将方法公开为公共的。

设想一个场景,您正在编写一个库来跟踪页面浏览量并显示每百万成本(CPM)印象。您希望向用户公开GetPageViews方法,而不是GetCPMRate方法。这是你怎么做的…

打开共享项目中的WinJSFundamentals.js文件,并用下面的代码片段替换它。

(function (global) {

// public method

function GetPageViews()

{

return 1000;

}

//private method.

function GetCPMRate()

{

return 1;

}

WinJS.Namespace.define("DeveloperPublish",

{

GetPageViews: GetPageViews

});

})(this);

console.log(DeveloperPublish.GetPageViews());

自执行匿名函数有两种方法:GetPageViewsGetCPMRateDeveloperPublish名称空间用于公开或导出GetPageViews函数,并为其提供公共访问。GetCPMRate则相反,是一种私有的方法。您可以在全局范围方法中调用GetCPMRate方法,但不能使用DeveloperPublish名称空间。例如,下面的代码片段演示了使用DeveloperPublish名称空间公开GetPageViewsGetTotalRate函数的场景;GetCPMRate仅在GetTotalRate内使用。

(function (global) {

// public method

function GetPageViews() {

return 1000;

}

//private method.

function GetCPMRate() {

return 2;

}

function GetTotalRate() {

return GetPageViews() * GetCPMRate();

}

WinJS.Namespace.define("DeveloperPublish",

{

GetPageViews: GetPageViews,

GetTotalRate: GetTotalRate

});

})(this);

console.log(DeveloperPublish.GetPageViews());

console.log(DeveloperPublish.GetTotalRate());

运行 Windows 项目。在图 2-6 中,您会看到GetPageViews方法在 Visual Studio JavaScript 控制台窗口中显示 1000。

A978-1-4842-0719-2_2_Fig6_HTML.jpg

图 2-6。

Display the string in the JavaScript console window in Visual Studio 2015

当你试图访问自执行匿名函数之外的GetCPMRate方法时,你会得到下面的错误(也见图 2-7 )。

A978-1-4842-0719-2_2_Fig7_HTML.jpg

图 2-7。

Error when trying to access private methods

0x800a1391: JavaScript runtime error: 'GetCPMRate' is undefined.

这是一个有用的特性,尤其是当您正在构建一个库,并且希望限制对 WinJS 中某些方法的访问时。

2.7 在 WinJS 中使用 Promise

问题

您需要异步执行代码,以便 UI 响应更快。

解决办法

您可以在通用 Windows 应用中使用异步编程,这样某些方法的处理就可以异步完成。通过这种方式,你的应用的 UI 线程是免费的,并且可以响应用户的输入。

它是如何工作的

WinJS 和通用 Windows 应用中的异步 API 被表示为承诺。WinJS 中 promise 的一个常见实现是xhr函数,它将 XMLHttpRequest 包装在 promise 中。当您提供一个 URL 和响应类型时,xhr函数返回承诺,通过返回数据来实现,或者如果失败则返回一个错误。

在这个菜谱中,您将构建一个应用,它只是将 URL 作为输入,并尝试连接到它。结果是基于连接的成功或失败。

在 Visual Studio 2015 中,启动在之前的配方中构建的现有通用 Windows 应用。打开default.html页面,在 body 部分下添加以下div元素。这接受了inputurl文本框中的 URL,状态显示在输出div标签中。

<div>

<input id="inputurl"/>

</div>

<div id="output">

</div>

您需要将 change 事件处理程序添加到 input 元素中,当用户输入文本并按下 Enter 键时,将会触发该事件处理程序。您可以在default.js文件的app.onactivated事件处理程序的WinJS.Utilities.ready函数中添加这个,如下所示。

WinJS.Utilities.ready(function () {

var input = document.getElementById("inputurl");

input.addEventListener("change", changeEvent);

}, false);

下一步是添加changeEvent函数,需要通过传递用户输入的 URL 来调用xhr函数;这相应地更新了结果。xhr函数的返回类型是 promise,它允许开发人员使用 promise 的then函数异步更新 UI。

then函数最多有三个参数,包括

  • 如果承诺无误地实现,则执行的completed功能
  • 处理错误的error函数
  • progress功能显示承诺的进度

让我们在app.onactivated事件之后将changeEvent添加到default.js文件中,如下所示。

function changeEvent(e) {

var resultDiv = document.getElementById("output");

WinJS.xhr({ url: e.target.value }).then(function completed(result) {

if (result.status === 200) {

resultDiv.style.backgroundColor = "Green";

resultDiv.innerText = "Success";

}

},

function error(e) {

resultDiv.style.backgroundColor = "red";

resultDiv.innerText = e.statusText;

});

}

该代码包括承诺的completederror功能。它根据结果显示文本成功或错误,并改变输出div元素的颜色。

在本地机器上构建并运行应用,输入 URL,然后按回车键。如果 URL 有效,输出div标签变成绿色并显示成功消息。如果有错误,错误信息以红色背景显示,如图 2-8 所示。

A978-1-4842-0719-2_2_Fig8_HTML.jpg

图 2-8。

Using the xhr function to demonstrate the promise

您可以通过使用 promise 对象的cancel方法来停止当前正在执行的异步操作。

xhrPromise.cancel();

注意,您还可以通过调用前面的then函数返回的承诺上的then来链接承诺操作。

三、基本 WinJS 控件

本章概述了 WinJS 库中可用的控件,开发人员可以使用这些控件快速构建他们的 Windows 应用。它探讨了如何向页面添加 WinJS 控件,以及基本的 WinJS 控件,如 ToggleSwitch、Rating、DatePicker、TimePicker、tooltip、text 控件等。

WinJS 中有一些高级控件,可以用来在应用中列出记录、显示菜单或添加工具栏。(第四章介绍了 ListView、工具栏和 AppBar 等高级控件。)

3.1 在页面上声明 WinJS 控件

问题

您需要在 Windows 应用的页面上添加或声明 WinJS 控件。

解决办法

使用div标记中的data-win-control属性在页面上添加 WinJS 控件。

它是如何工作的

Create a new project using the Windows Universal (Blank App) template in Microsoft Visual Studio 2015. This creates a universal app that can be run on Windows tablets and Windows Mobile powered by Windows 10.   Open the default.html page from the project in Visual Studio Solution Explorer.   Declare a WinJS control on a page by using the data-win-control attribute. For example, to declare the Rating Control on a page, add the following div tag.

<div id="rating" data-win-control="WinJS.UI.Rating"></div>

在这个代码片段中,div标记充当 WinJS 控件的占位符。data-win-control属性用于指示将要呈现的 WinJS 控件。

HTML 页面将如下所示。

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8" />

<title>Recipe3.1</title>

<!-- WinJS references -->

<link href="WinJS/css/ui-light.css" rel="stylesheet" />

<script src="WinJS/js/base.js"></script>

<script src="WinJS/js/ui.js"></script>

<!-- Recipe3.1 references -->

<link href="/css/default.css" rel="stylesheet" />

<script src="/js/default.js"></script>

</head>

<body class="win-type-body">

<div id="rating" data-win-control="WinJS.UI.Rating"></div>

</body>

</html>

在页面上使用 WinJS 控件的主要要求是包含 JavaScript 和 CSS 文件。您应该在 HTML 页面的 head 部分添加以下引用。

<link href="WinJS/css/ui-light.css" rel="stylesheet" />

<script src="WinJS/js/base.js"></script>

<script src="WinJS/js/ui.js"></script>

WinJS 库提供了两个 CSS(层叠样式表)文件:ui-dark.cssui-light.css。通过分别切换到ui-light.cssui-dark.css,您可以在所有控件的亮主题和暗主题之间切换。

base.jsui.js文件是 JavaScript 文件,需要在 HTML 页面中引用以使用 WinJS 控件。WinJS 控件的 JavaScript 源代码在这些 JavaScript 文件之一中定义。

在调用WinJS.UI.processAll方法之前,WinJS 控件(在本例中,它是 Rating 控件)不会被呈现。该方法在项目的js文件夹下的default.js文件中定义。WinJS.UI.processAll方法的主要功能是解析 HTML 页面,用data-win-control识别属性,并相应地生成控件。

因此,有必要在页面上包含对default.js文件的引用。

现在,让我们构建通用应用,并在 Windows 10 和 Windows Mobile 模拟器上运行它。

图 3-1 展示了分级控件在 Windows 平板电脑上的外观。图 3-2 展示了分级控件在 Windows Mobile 上的外观。

A978-1-4842-0719-2_3_Fig2_HTML.jpg

图 3-2。

Rating control on Windows Mobile emulator

A978-1-4842-0719-2_3_Fig1_HTML.jpg

图 3-1。

Rating control on Windows 10

3.2 WinJS 控件的设置选项

问题

您希望为 HTML 页面上的 WinJS 控件设置附加选项或属性。

解决办法

使用data-win-options属性为控件设置附加选项或属性。

它是如何工作的

大多数 WinJS 控件支持设置 options 属性。例如,在页面上使用分级控件时,您可能希望限制用户可以提供的最高分级。

您可以用data-win-options属性来指定这一点。例如,下面的 HTML 代码演示了如何将分级控件的最高分级设置为 4。

<div id="rating" data-win-control="WinJS.UI.Rating"

data-win-options="{maxRating:4}">

</div>

data-win-options采用 JavaScript 选项;它与属性名一起传递,其值用花括号括起来。

在这里,maxRating是一个属性。也可以传递多个属性及其值。例如,如果您需要设置enableClear属性和MaxRating,您可以用data-win-options属性来设置它,如下所示。

<div id="rating" data-win-control="WinJS.UI.Rating"

data-win-options="{maxRating:4,enableClear:false}">

</div>

图 3-3 展示了窗口移动仿真器上的屏幕及其显示。

A978-1-4842-0719-2_3_Fig3_HTML.jpg

图 3-3。

Rating control with maximum rating of 4

如果enableClear属性设置为 true,那么用户可以滑动到控件的左侧来清除评级值。

3.3 从 JavaScript 代码添加 WinJS 控件

问题

您需要从 JavaScript 代码中添加一个 WinJS 控件,而不是将其添加到 HTML 页面中。

解决办法

您可以强制创建控件;即完全使用 JavaScript 来识别div元素并动态生成控件并添加到页面中。

它是如何工作的

Create a new project using the Windows Universal (Blank App) template in the Visual Studio 2015 Community. This creates a Windows universal app that can be run on Windows tablets or on Windows Mobile running in Windows 10.   Open the project’s default.html page from the project in Visual Studio Solution Explorer.   Add a div tag in the body section of the page where you want the control to be rendered. <div id="rating" >     </div>   Right-click the js folder within the project in the Solution Explorer. Select Add ➤ New JavaScript File and provide a name for the file. In this example, let’s name the file controldemo.js. This adds the controldemo.js file under the js folder of the project.   Add the following code to the controldemo.js file. This creates a new rating control and adds it to the rating div tag. (function () {     "use strict";     function AddControl()     {         var ratingDiv = document.getElementById("rating");         var ratingCtrl = new WinJS.UI.Rating(ratingDiv);     }     document.addEventListener("DOMContentLoaded", AddControl); })(); The preceding code creates a new instance of the WinJS.UI.Rating JavaScript class. It is created by passing the rating div element to the constructor of the Rating class.   Now you need to add a reference to the controldemo.js file in the HTML page. Open the default.html file and add the following code snippet to the head section of the page. <script src="/js/controldemo.js"></script>

页面将包含代码,如下所示。

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8" />

<title>Recipe3.3</title>

<!-- WinJS references -->

<link href="WinJS/css/ui-light.css" rel="stylesheet" />

<script src="WinJS/js/base.js"></script>

<script src="WinJS/js/ui.js"></script>

<!-- Recipe3.3 references -->

<link href="/css/default.css" rel="stylesheet" />

<script src="/js/default.js"></script>

<script src="/js/controldemo.js"></script>

</head>

<body class="win-type-body">

<div id="rating">

</div>

</body>

</html>

让我们在 Windows Mobile 模拟器上运行应用。图 3-4 展示了 Windows Mobile 上的输出页面。

A978-1-4842-0719-2_3_Fig4_HTML.jpg

图 3-4。

Rating control added from the JavaScript code

控件的选项或属性也可以通过 JavaScript 代码强制设置。下面展示了如何从 JavaScript 代码中创建 Rating 控件的实例并设置maximumRating属性。

(function () {

"use strict";

function AddControl()

{

var ratingDiv = document.getElementById("rating");

var ratingCtrl = new WinJS.UI.Rating(ratingDiv);

ratingCtrl.maxRating = 4;

}

document.addEventListener("DOMContentLoaded", AddControl);

})();

这段代码片段展示了如何设置maxRating属性,而不在构造函数中设置它。或者,您也可以通过将它传递给第二个参数来设置它,用花括号括起来。

图 3-5 演示了在 Visual Studio 中设置分级控制属性时的智能感知支持。

A978-1-4842-0719-2_3_Fig5_HTML.jpg

图 3-5。

IntelliSense support in Visual Studio 2015

Intellisense 是 Microsoft Visual Studio 中的一项重要功能,它可以提高开发人员的工作效率,并根据用户在 IDE 中键入的内容向开发人员提供自动建议。

3.4 从 HTML 文档中获取 WinJS 控件

问题

您希望从 HTML 页面获取控件,并使用 JavaScript 代码设置属性。

解决办法

使用winControl属性从页面的DOM元素获取控件。

它是如何工作的

Create a new project using the Windows Universal (Blank App) template in Visual Studio 2015 Community. This creates a Windows universal app that can be run on Windows tablets and Windows Mobile running Windows 10.   Open the default.html page from the project in Visual Studio Solution Explorer.   Add the Rating control to the body section of the page. <div id="rating" data-win-control="WinJS.UI.Rating" >     </div>   Right-click on the js folder within the project in the Solution Explorer. Select Add ➤ New JavaScript File and provide a name for the file. In this example, let’s name the file controldemo.js. This adds the controldemo.js file under the js folder of the project.   Add the following code to the controldemo.js file. (function () {     "use strict";     function GetControl() {         WinJS.UI.processAll().done(function () {             var ratingControl = document.getElementById("rating").winControl;             ratingControl.userRating = 2;         });     }     document.addEventListener("DOMContentLoaded", GetControl); })();   When you invoke the document.getElementById method, you get the DOM element. You need to use the winControl property to get the associated control.   This needs to be surrounded by the WinJS.UI.processAll method, which returns the promise. The reason for surrounding your logic with the processAll method is that you have to wait until all the controls are created and parsed in the document before trying to retrieve it.   Once the Rating control is retrieved, you can start setting the values to the properties of the Rating control instance. In this example, you are setting the user rating to 2.   Finally, you need to add the reference of the controldemo.js file in the default.html page. Open the default.html page from Visual Studio Solution Explorer and add the following code to the head tag. <script src="/js/controldemo.js"></script>

当您在 Windows Mobile 模拟器上运行应用时,您应该会看到如图 3-6 所示的屏幕。

A978-1-4842-0719-2_3_Fig6_HTML.jpg

图 3-6。

Windows Mobile emulator displaying the Rating control with value 2

3.5 拨动开关控制

问题

您需要为用户提供一个在屏幕上执行二进制操作的选项。例如,您需要为用户提供打开或关闭服务的选项。

解决办法

使用 WinJS 中的 ToggleSwitch 控件。它类似于标准的复选框控件,但具有更好的触摸支持。您只需用手指滑过 ToggleSwitch 控件即可选中或取消选中该选项。您可以使用 WinJS 在页面上声明 ToggleSwitch 控件。将 UI.ToggleSwitch 值赋给div元素的data-win-control属性。

它是如何工作的

下面演示如何在页面上声明 ToggleSwitch 控件。

<div id="locationServices" data-win-control="WinJS.UI.ToggleSwitch"

data-win-options="{

title :'Location Services',

labelOff: 'Disabled',

labelOn:'Enabled',

checked: true

}">

</div>

当在 Windows 平板电脑或 Windows Mobile 模拟器上执行时,前面的代码片段将如图 3-7 所示。

A978-1-4842-0719-2_3_Fig7_HTML.jpg

图 3-7。

ToggleSwitch on the Windows Mobile and Windows emulator

data-win-options属性用于设置 ToggleSwitch 控件的附加属性。在前面的例子中,像标题、labelOfflabelOnChecked这样的属性是使用这个属性设置的。

title 为 ToggleSwitch 设置标题内容。labelOfflabelOn属性根据控件的选中(开)和未选中(关)状态标识需要显示在 ToggleSwitch 旁边的文本。

使用控件的 checked 属性可以找到 ToggleSwitch 的当前状态(选中或未选中)。

让我们向项目的js文件夹添加一个新的 JavaScript 文件,并将其命名为 controldemo.js。打开default.html页面,添加 ToggleSwitch 控件和一个空的div标签,以显示切换开关状态变化的消息。

default.html看起来如下。

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8" />

<title>Recipe3.5</title>

<!-- WinJS references -->

<link href="WinJS/css/ui-light.css" rel="stylesheet" />

<script src="WinJS/js/base.js"></script>

<script src="WinJS/js/ui.js"></script>

<!-- Recipe3.5 references -->

<link href="/css/default.css" rel="stylesheet" />

<script src="/js/default.js"></script>

<script src="/js/controldemo.js"></script>

</head>

<body class="win-type-body">

<div id="locationServices" data-win-control="WinJS.UI.ToggleSwitch"

data-win-options="{

title :'Location Services',

labelOff: 'Disabled',

labelOn:'Enabled',

checked: true

}">

</div>

<div id="info"></div>

</body>

</html>

为了从 JavaScript 代码中识别状态,您需要连接 ToggleSwitch 控件的 change 事件处理程序。当您更改控件的状态时,会触发此事件。

打开controldemo.js文件,用下面的代码替换它。

(function () {

"use strict";

function GetControl() {

WinJS.UI.processAll().done(function () {

var toggleButton = document.getElementById("locationServices").winControl;

var InfoElement = document.getElementById("info");

toggleButton.addEventListener('change', function (args) {

if (toggleButton.checked) {

InfoElement.innerHTML = "Location Services enabled";

}

else {

InfoElement.innerHTML = "Location Services disabled";

}

})

});

}

document.addEventListener("DOMContentLoaded", GetControl);

})();

当您在 Windows 10 模拟器和 Windows Mobile 模拟器上运行应用时,您将看到如图 3-8 所示的屏幕。

A978-1-4842-0719-2_3_Fig8_HTML.jpg

图 3-8。

ToggleSwitch with the change event.

当您切换控件时,适当的消息会显示在Info div元素中。

3.6 日期选择器控件

问题

您希望允许用户从应用页面选择日期。

解决办法

使用允许用户选择日期的 WinJS DatePicker 控件。该控件显示三个列表:月、日和年各一个。

它是如何工作的

您可以在页面上声明 DatePicker 控件,如下所示。

<div id="Birthday" data-win-control="WinJS.UI.DatePicker" >

</div>

在这个菜谱中,让我们尝试在页面上添加 DatePicker 控件,并在 JavaScript 代码中绑定事件,以在一个div元素中显示所选日期。

Create a new project using the Windows Universal App template in Visual Studio 2015.   Open the default.html page and replace it with the following. <!DOCTYPE html> <html> <head>     <meta charset="utf-8" />     <title>Recipe3.6</title>     <!-- WinJS references -->     <link href="WinJS/css/ui-light.css" rel="stylesheet" />     <script src="WinJS/js/base.js"></script>     <script src="WinJS/js/ui.js"></script>     <!-- Recipe3.6 references -->     <link href="/css/default.css" rel="stylesheet" />     <script src="/js/default.js"></script>     <script src="/js/controldemo.js"></script> </head> <body class="win-type-body">     <div id="Birthday" data-win-control="WinJS.UI.DatePicker">     </div>     <div id="info"></div> </body> </html> The default.html page contains the DatePicker control as well as the div tag with the name information to display the selected date. The controldemo.js file is referenced, which you create next.   Add a new JavaScript file to the project’s js folder from Visual Studio Solution Explorer and name it controldemo.js. Add the following JavaScript code to the controldemo.js file. (function () {     "use strict";     function GetControl() {         WinJS.UI.processAll().done(function () {             var datepick = document.getElementById("Birthday").winControl;             var InfoEelement = document.getElementById("info");             datepick.addEventListener('change', function (args) {                 InfoEelement.innerHTML = "The selected date is " +                     datepick.current.toDateString();             })         });     }     document.addEventListener("DOMContentLoaded", GetControl); })();

只要您更改日期、月份或年份,DatePicker 就会引发 change 事件。您可以通过处理该事件来获取当前选定的日期。

在 JavaScript 代码中,document.getElementByIdwinControl属性用于从 HTML 页面获取 DatePicker。从 DatePicker 控件调用addEventListener方法来订阅变更事件。

使用 DatePicker 的 current 属性检索选定的日期。

在 Windows Mobile 或 Windows 10 上运行应用会显示日期选择器,并显示所选日期,如图 3-9 所示。

A978-1-4842-0719-2_3_Fig9_HTML.jpg

图 3-9。

DatePicker control demo

通过分配格式字符串,可以控制 DatePicker 控件的年、月和日期字段的外观。

例如,可以对 DatePicker 进行格式化,以两位数格式显示缩写的月份和年份以及日期,如下所示。

<div id="Birthday" data-win-control="WinJS.UI.DatePicker"

data-win-options="{

monthPattern : '{month.abbreviated}',

datePattern: '{day.integer(2)}',

yearPattern: '{year.abbreviated}'

}">

</div>

使用monthPatterndatePatternyearPattern属性设置格式。

monthPattern属性定义了月份的显示模式。您可以使用表 3-1 中显示的值之一设置月模式属性。

表 3-1。

Month Pattern for the date picker

| 模式 | 描述 | | --- | --- | | 完整月份 | 这将显示月份的全名。 | | 月份。缩写(n) | 您可以使用带或不带参数的 month .缩写。参数指定一个月的字母数。 | | month.solo .完整 | 这表示适合独立显示的月份。并且,month . solo . abstracted 可以带参数使用,也可以不带参数使用。 | | 月.整数(n) | month.integer 用于指定月字段中显示的整数个数。 |

datePattern属性用于获取或设置 DatePicker 控件中日期的显示模式。您可以用表 3-2 中显示的值之一设置datePattern

表 3-2。

Date Pattern for the date picker

| 模式 | 描述 | | --- | --- | | day .整数(n) | 您可以使用带参数或不带参数的 day.integer。参数指定要包含的前导零;例如,如果值为 day.integer (2 ),则显示 02。 | | dayofweek .缩写 | 此属性显示一周中的某一天。参数指定要显示的字母数。 |

属性获取或设置年份的显示模式。默认的年模式是 year.full。您可以将其修改为表 3-3 中显示的任一值。

表 3-3。

Year pattern for the date picker

| 模式 | 描述 | | --- | --- | | 全年 | 以数字显示完整的年份 | | 年份。缩写(n) | 用指定的一组数字显示年份。 |

3.7 时间选择器控件

问题

您希望允许用户从应用页面选择时间。

解决办法

使用允许用户选择时间的 WinJS TimePicker 控件。该控件显示三个列表:小时、分钟和时间段(AM/PM)各一个。

它是如何工作的

您可以在页面上声明 DatePicker 控件,如下所示。

<div id="timeSelector" data-win-control="WinJS.UI.TimePicker" >

</div>

在这个菜谱中,让我们尝试在页面上添加 TimePicker 控件,并在 JavaScript 代码中绑定事件,以在一个div元素中显示所选时间。

Create a new project using the Windows Universal App template in Visual Studio 2015.   Open the default.html page and replace it with the following. <!DOCTYPE html> <html> <head>     <meta charset="utf-8" />     <title>BasicControls</title>     <!-- WinJS references -->     <link href="WinJS/css/ui-light.css" rel="stylesheet" />     <script src="WinJS/js/base.js"></script>     <script src="WinJS/js/ui.js"></script>     <!-- Recipe3.7 references -->     <link href="/css/default.css" rel="stylesheet" />     <script src="/js/default.js"></script>     <script src="/js/controldemo.js"></script> </head> <body class="win-type-body">     <div id="timeSelector" data-win-control="WinJS.UI.TimePicker">     </div>     <div id="info"></div> </body> </html> The default.html page contains the TimePicker control as well as the div tag with the name information to display the selected time. The controldemo.js file is referenced, which you will create in the next step.   Add a new JavaScript file to the project’s js folder from the Visual Studio Solution Explorer and name it controldemo.js. Replace the file with the following JavaScript code. (function () {     "use strict";     function GetControl() {         WinJS.UI.processAll().done(function () {             var datepick = document.getElementById("timeSelector").winControl;             var InfoEelement = document.getElementById("info");             datepick.addEventListener('change', function (args) {                 InfoEelement.innerHTML = "The selected time is " +                     datepick.current.toTimeString();             })         });     }     document.addEventListener("DOMContentLoaded", GetControl); })();

只要您更改了小时、分钟或时间段,TimePicker 就会引发 change 事件。您可以通过处理该事件来获取当前选定的时间。

在 JavaScript 代码中,document.getElementByIdwinControl属性用于从 HTML 页面获取时间选择器。从 TimePicker 控件调用addEventListener方法来订阅变更事件。

使用 TimePicker 控件的 current 属性检索选定的时间。

在 Windows Mobile 或 Windows 10 上运行应用会显示时间选择器并显示所选时间,如图 3-10 所示。

A978-1-4842-0719-2_3_Fig10_HTML.jpg

图 3-10。

TimePicker control demo

通过使用data-win-options属性设置 clock 属性,可以将 TimePicker 设置为支持 24 小时制,如下所示。

<div id="timeSelector" data-win-control="WinJS.UI.TimePicker"

data-win-options="{

clock : '24HourClock',

minuteIncrement : 15

}">

</div>

可以用minuteIncrement属性控制分钟列表的增量值,如下所示。

当您在 Windows 10 或 Windows Mobile 10 上运行该页面时,您会看到如图 3-11 所示的屏幕。

A978-1-4842-0719-2_3_Fig11_HTML.jpg

图 3-11。

TimePicker with the 24-hour clock format and timeInterval adjustment

通过分配格式字符串,可以控制 TimePicker 控件的小时、分钟和周期字段的外观。

使用hourPatternminutePatternperiodPattern属性设置格式。

hourPattern属性设置小时的显示模式。hourPattern属性的默认值是 hour.integer(2 ),您可以通过更改参数值来修改hourPattern属性。属性获取或设置分钟的显示模式。此属性的默认值是 minute.integer (2 ),您可以通过更改参数中的整数数目来修改此模式。periodPattern属性获取或设置周期的显示模式;该属性的默认值是 period.abbreviated (2)。您可以通过更改参数值来修改此属性的模式。

表 3-4。

Pattern for hours, minutes and period in timepicker

| 模式 | 描述 | | --- | --- | | hour.integer(n) | 这将显示小时的指定位数。 | | {minute.integer(n)} | 这将显示分钟的指定位数。 | | {句点.缩写(n)} | 基于作为参数传递的值的期间显示模式。 |

3.8 工具提示控件

问题

当用户将鼠标悬停在页面上的任何元素上时,您需要显示工具提示。

解决办法

使用 WinJS Tooltip 控件在页面上的 HTML 元素上显示工具提示。当您将光标悬停在某个元素上时,工具提示会显示指定的秒数。当用户将光标从元素上移开时,工具提示应该会消失。

它是如何工作的

为按钮添加工具提示控件,如下所示:

<button id="btnSave"

data-win-control="WinJS.UI.Tooltip"

data-win-options="{

innerHTML: 'Saves the <b>Employee</b> record'}">

Save

</button>

通过data-win-options属性设置innerHTML属性,该属性设置工具提示控件的文本。这个文本也可以包含 HTML 标签。

图 3-12 展示了工具提示在 Windows Mobile 10 和 Windows 10 平板电脑上的显示方式。

A978-1-4842-0719-2_3_Fig12_HTML.jpg

图 3-12。

Tooltip displayed within the app

您可以通过修改win-tooltip CSS 类来自定义工具提示控件的样式。

从 CSS 文件夹中打开default.css文件,并将以下代码添加到文件的末尾。

.win-tooltip

{

background-color: bisque;

border-radius:30px;

border-color:red;

}

图 3-13 展示了定义了前面提到的样式后工具提示控件的外观。

A978-1-4842-0719-2_3_Fig13_HTML.jpg

图 3-13。

Tooltip with styling

注意,当使用 div 元素作为工具提示的容器时,需要将其 display 属性设置为 inline block,因为 div 元素的显示设置默认为 block。

3.9 显示文本

问题

您需要在 Windows 应用的页面上显示文本或标签。

解决办法

使用传统的 HTML 元素或标签在 Windows 应用的页面上显示文本。这些包括 div、标签、段落、标题等等。

它是如何工作的

HTML 元素(如标签、div、段落、标题等)是使用 JavaScript 在 Windows 通用应用上显示只读文本的一些常用控件。

您可以定义一个简单的 label 控件并设置其文本,如下所示。

<label>Welcome to the Windows 10 App Development World</label>

<div>by Microsoft MVPs</div>

可以使用两种方法之一将样式应用于显示文本:inline 或 CSS。

下面的代码片段演示了如何使用 inline style 属性来格式化文本。

<div style="font-family:Verdana">Welcome to the Windows 10 App Development World</div>

<p style="margin:0px; color:blue; font-family:Arial; font-size:18px">Welcome to the Windows 10 App Development World</p>

图 3-14 展示了使用内嵌样式属性的上述代码的输出。

A978-1-4842-0719-2_3_Fig14_HTML.jpg

图 3-14。

Styling the read-only text

CSS 允许开发人员在一个地方定义一个样式,然后在多个控件中重复使用。

3.10 在应用中编辑文本

问题

您需要允许用户在您的 Windows 应用页面上输入文本。

解决办法

使用 HTML 元素允许用户在页面上输入文本。这包括文本框、文本区域、密码输入框、富文本框等等。

它是如何工作的

使用 JavaScript 的 Windows 通用应用有四种不同类型的文本输入元素。

  • 文本框:该控件允许用户在单行中输入或编辑纯文本。
  • 文本区域:该控件支持多行,允许用户输入或编辑纯文本。
  • 密码输入框:该控件允许用户输入密码。
  • 格式文本框:该控件允许用户编辑需要格式化的文本。

这是一个简单的文本框、文本区域和密码输入框的 HTML。

<div><textarea id="textarea1" rows="2"></textarea></div>

<div><input type="text" /></div>

<div><input id="password" type="password" placeholder="Enter password" /></div>

图 3-15 展示了控件在 Windows Mobile 10 模拟器上的显示方式。

A978-1-4842-0719-2_3_Fig15_HTML.jpg

图 3-15。

Editable controls

一旦用户执行了一些动作,比如点击按钮,你就可以从 JavaScript 代码中获取控件的内容,如方法 3-4 所示。

四、列表控件、应用栏和工具栏

本章重点介绍与数据采集相关的控件,包括 Repeater、FlipView 和 ListView。本章还介绍了菜单相关控件的制作方法,如应用栏、工具栏、弹出菜单、上下文菜单和菜单输出。

4.1 使用中继器控制

问题

您需要使用 WinJS Repeater 控件在用户界面(UI)上显示数据集合。

解决办法

Repeater 控件是 WinJS 库中可用于在 UI 上显示集合数据的控件之一。您可以通过将data-win-control属性设置为 WinJS 来添加 Repeater 控件。容器的值,然后通过使用data-win-bind属性将属性绑定到 UI 中的控件。

它是如何工作的

为了演示 Repeater 控件的使用,让我们构建一个通用的 Windows 应用,显示一个雇员列表的 HTML 表,如图 4-1 所示。

A978-1-4842-0719-2_4_Fig1_HTML.jpg

图 4-1。

HTML table with a Repeater control

启动 Visual Studio 2015,并使用 JavaScript 模板创建一个新的 Windows 通用项目。

打开default.html页面,用下面的代码片段替换它。

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8" />

<title>Recipe4.1</title>

<!-- WinJS references -->

<link href="WinJS/css/ui-light.css" rel="stylesheet" />

<script src="WinJS/js/base.js"></script>

<script src="WinJS/js/ui.js"></script>

<link href="/css/default.css" rel="stylesheet" />

<script src="/js/default.js"></script>

<script src="/js/data.js"></script>

</head>

<body style="margin:20px">

<h1>Recipe 4.1</h1>

<table>

<thead>

<tr>

<th> Employee ID</th>

<th> Employee Name</th>

<th> Employee Designation</th>

</tr>

</thead>

<tbody id="repeaterData" data-win-control="WinJS.UI.Repeater">

<tr>

<td data-win-bind="textContent:id"></td>

<td data-win-bind="textContent:name"></td>

<td data-win-bind="textContent:designation"></td>

</tr>

</tbody>

</table>

</body>

</html>

在前面的代码片段中,Repeater 控件被添加到 body 部分;而 Repeater 控件的内部内容被用作模板。来自 repeater 数据的每一行都显示在 HTML 表的 body 部分。

前面的 HTML 页面引用了一个data.js页面。让我们将这个文件添加到项目中。向项目的js文件夹中添加一个新的 JavaScript 文件,并将其命名为 data.js。

(function () {

"use strict";

function Initialize() {

WinJS.UI.processAll().done(function () {

var repeaterControl1 = document.getElementById('repeaterData').winControl;

var Employees = new WinJS.Binding.List([

{ id: 1, name: "Senthil Kumar", designation: "Mobile Developer" },

{ id: 2, name: "Lohith GN", designation: "Web Developer" },

{ id: 3, name: "Vidyasagar", designation: "Game Developer" }

]);

repeaterControl1.data = Employees;

})

}

document.addEventListener("DOMContentLoaded", Initialize);

})();

WinJS.Binding.List用于绑定中继器控件。在前面的代码片段中,Repeater 控件被绑定到 employees 列表,该列表表示雇员数据的集合。employee 对象包含以下属性:id、姓名和职务。使用 Repeater 控件的 data 属性绑定数据。

在 Windows Mobile 模拟器上运行应用。您应该会看到如图 4-2 所示的屏幕。

A978-1-4842-0719-2_4_Fig2_HTML.jpg

图 4-2。

Repeater control in Windows Mobile 10

如果希望 Repeater 控件中的项可调用或可选择,其中一个选择是在 Repeater 控件模板中使用 ItemContainer 控件。

下面的示例演示 ItemContainer 在 Repeater 控件中的用法,该控件绑定到雇员列表。

<div id="repeaterData" data-win-control="WinJS.UI.Repeater">

<div data-win-control="WinJS.UI.ItemContainer" data-win-bind="dataset.name:name">

<div data-win-bind="textContent:name"></div>

</div>

</div>

ItemContainer 有一个名为data-win-bind="dataset.name: name"属性的属性,它将雇员列表中每一项的名称与 ItemContainer 相关联。

Repeater 控件被绑定到 JavaScript 文件中的雇员列表,如下所示。

(function () {

"use strict";

function Initialize() {

WinJS.UI.processAll().done(function () {

var repeaterControl1 = document.getElementById('repeaterData').winControl;

var Employees = new WinJS.Binding.List([

{ id: 1, name: "Senthil Kumar", designation: "Mobile Developer" },

{ id: 2, name: "Lohith GN", designation: "Web Developer" },

{ id: 3, name: "Vidyasagar", designation: "Game Developer" }

]);

repeaterControl1.data = Employees;

repeaterControl1.addEventListener("invoked",function(e)

{

var name = e.target.dataset.name;

var message = new Windows.UI.Popups.MessageDialog(name);

message.showAsync();

})

})

}

document.addEventListener("DOMContentLoaded", Initialize);

})();

当您在 Windows 中运行应用时,您会看到三个项目正在呈现。如果点击一个项目,会显示一个带有项目名称的消息框,如图 4-3 所示。

A978-1-4842-0719-2_4_Fig3_HTML.jpg

图 4-3。

Item in the Repeater control that is invokable

4.2 使用 FlipView 控件

问题

您只需要显示集合中的单个项目。

解决办法

使用 WinJS 中的 FlipView 控件,该控件一次仅显示集合中的单个项目。FlipView 控件的一个用例是一个照片库应用,用户可以在其中选择一个图像,然后在图像列表中滑动。

虽然一次只显示一项,但 FlipView 控件显示箭头,使您可以移动到数据源中的下一项或上一项。

通过用 WinJS 设置div元素的data-win-control属性,可以将 ListView 控件添加到页面中。列表视图值。

它是如何工作的

让我们在 Visual Studio 2015 中创建新的 Windows 通用项目。在js文件夹下将新的 JavaScript 文件命名为 data.js。这个 JavaScript 文件将包含可以在 ListView 中列出的数据。将下面的代码片段添加到data.js文件中。

(function () {

"use strict";

var Employees = new WinJS.Binding.List([

{ id: 1, name: "Senthil Kumar", designation: "Mobile Developer" },

{ id: 2, name: "Lohith GN", designation: "Web Developer" },

{ id: 3, name: "Vidyasagar", designation: "Game Developer" }

]);

WinJS.Namespace.define("recipeData",

{

Employees :Employees

});

})();

前面的 JavaScript 包含一个雇员集合;每个雇员都有一个 id、一个姓名和一个指定属性。

现在,您希望在 Windows 应用中一次显示一名员工。下面的 HTML 代码片段说明了如何使用 FlipView 控件显示雇员列表中的单个雇员。

请注意,该页面包含对data.js文件的引用,该文件包含 FlipView 控件的数据。

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8" />

<title>Recipe4.2</title>

<!-- WinJS references -->

<link href="WinJS/css/ui-light.css" rel="stylesheet" />

<script src="WinJS/js/base.js"></script>

<script src="WinJS/js/ui.js"></script>

<!-- Recipe4.2 references -->

<link href="/css/default.css" rel="stylesheet" />

<script src="/js/default.js"></script>

<script src="/js/data.js"></script>

</head>

<body class="win-type-body" style="margin:20px">

<h1>Recipe 4.2</h1>

<div id="template" data-win-control="WinJS.Binding.Template">

<div>

<h4 data-win-bind="innerText: name"></h4>

<h6 data-win-bind="innerText: designation"></h6>

</div>

</div>

<div id="flipView1"

data-win-control="WinJS.UI.FlipView"

data-win-options="{itemTemplate: select('#template') ,

itemDataSource : recipeData.Employees.dataSource}">

</div>

</body>

</html>

当您在 Windows 上运行该应用时,您应该会看到如图 4-4 所示的页面。

A978-1-4842-0719-2_4_Fig4_HTML.jpg

图 4-4。

FlipView in the WinJS app

FlipView 是用下面的 HTML 标记声明的。

<div id="flipView1"

data-win-control="WinJS.UI.FlipView"

data-win-options="{itemTemplate: select('#template') ,

itemDataSource : recipeData.Employees.dataSource}">

</div>

使用itemDataSource属性将 FlipView 绑定到雇员列表。在前面的代码片段中,FlipView 绑定到雇员列表,其类型为 WinJS.Binding.List。

请注意,FlipView 显示来自实现 IListDataSource 接口的数据源的数据。这方面的一个例子包括 WinJS。Binding.List 和 WinJS.UI.StorageDataSource。

此外,FlipView 的itemTemplate属性被设置为 id 为template的 TemplateControl。它包含用于格式化 ListView 中显示的员工详细信息的模板。在本例中,模板被配置为显示名称和称号。

4.3 使用 ListView 控件

问题

您需要在页面上显示一个交互式项目列表。

解决办法

使用 ListView 控件,它为开发人员提供了许多列出项目的选项,以及其他选项,如选择、排序、筛选、分组等。通过用 WinJS 设置data-win-bind属性,可以将 ListView 添加到页面中。列表视图值。

它是如何工作的

ListView 控件是 Windows 应用中最常用的控件之一。可以将 ListView 控件绑定到实现 IListDataSource 接口的数据源。目前,WinJS 有两个实现 IListDataSource 接口的对象。

  • WinJS。绑定.列表
  • WinJS。UI.StorageDataSource

在这个食谱中,我们将重点介绍如何使用 WinJS。绑定。列表数据源。

让我们看看如何在 WinJS 中使用 ListView 控件。绑定。列表数据源。

在 Visual Studio 2015 中新建一个 Windows 通用应用,打开default.html页面。用下面的代码替换它。

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8" />

<title>Recipe4.3</title>

<!-- WinJS references -->

<link href="WinJS/css/ui-light.css" rel="stylesheet" />

<script src="WinJS/js/base.js"></script>

<script src="WinJS/js/ui.js"></script>

<!-- Recipe4.3 references -->

<link href="/css/default.css" rel="stylesheet" />

<script src="/js/default.js"></script>

<script src="/js/data.js"></script>

</head>

<body class="win-type-body">

<h1>Recipe 4.3</h1>

<div id="template" data-win-control="WinJS.Binding.Template">

<div>

<h4 data-win-bind="innerText: name"></h4>

<h6 data-win-bind="innerText: designation"></h6>

</div>

</div>

<div id="listView1"

data-win-control="WinJS.UI.ListView"

data-win-options="{itemTemplate: select('#template')}">

</div>

</body>

</html>

下面的代码用于将 ListView 控件添加到页面中。

<div id="listView1"

data-win-control="WinJS.UI.ListView"

data-win-options="{itemTemplate: select('#template')}">

</div>

前面的代码片段中显示的 ListView 控件使用模板来显示每个雇员。

注意,您已经在 HTML 页面中引用了data.js文件。该文件包含雇员数组。向项目的js文件夹中添加一个新的 JavaScript 文件,并将其命名为 data.js。

(function () {

"use strict";

function Initialize() {

WinJS.UI.processAll().done(function () {

var listControl1 = document.getElementById('listView1').winControl;

var Employees = new WinJS.Binding.List([

{ id: 1, name: "Senthil Kumar", designation: "Mobile Developer" },

{ id: 2, name: "Lohith GN", designation: "Web Developer" },

{ id: 3, name: "Vidyasagar", designation: "Game Developer" },

{ id: 4, name: "Michael", designation: "Architect" }

]);

listControl1.itemDataSource = Employees.dataSource;

listControl1.addEventListener("iteminvoked", function (e) {

var index = e.detail.itemIndex;

e.detail.itemPromise.then(function (item) {

var message = new Windows.UI.Popups.MessageDialog(item.data.name);

message.showAsync();

})

})

})

}

document.addEventListener("DOMContentLoaded", Initialize);

})();

从 employees 数组中创建一个列表,该数组使用itemDataSource属性绑定到 ListView 控件。

当您运行应用时,您会看到以列表视图显示的员工数据。

JavaScript 代码还包括处理 ListView 的调用事件的代码,该事件显示从列表中选择的雇员。

ListView 控件在内部对每个 ListView 项使用 ItemContainer 控件。您可以处理 ListView 控件的 item-invoked 事件,以检测何时单击了特定的 ListView 项。

图 4-5 显示了在 Windows 中呈现的屏幕,其中包含该食谱中的代码片段。

A978-1-4842-0719-2_4_Fig5_HTML.jpg

图 4-5。

ListView control in Windows app with the invoked event handling

ListView 控件支持不同的布局,这些布局可以决定控件的整体外观。这些布局包括

  • 网格布局
  • 列表布局
  • 跨单元布局

网格布局以网格格式显示 ListView 项,包含行和列。列表布局在单个列表中显示列表项。跨单元格布局将列表项显示为网格布局,但支持多列单元格。

要将 ListView 设置为网格布局,请将layout属性设置为 WinJS。在the data-win-options属性下的 UI.GridLayout,如下所示。

<div id="listView1"

data-win-control="WinJS.UI.ListView"

data-win-options="{itemTemplate: select('#template'),

layout : {type:WinJS.UI.GridLayout,maximumRowsOrColumns : 1}}">

</div>

图 4-6 显示了使用网格布局时呈现的用户界面。

A978-1-4842-0719-2_4_Fig6_HTML.jpg

图 4-6。

Grid layout in ListView

您也可以将布局设置为以下值:

  • WinJS.UI .储存格扩充配置
  • WinJS.UI.ListLayout

4.4 过滤 ListView 控件中的项目

问题

您需要通过从与 ListView 关联的数据源中过滤列表视图中显示的项目来过滤它。

解决办法

你可以使用 WinJS。然后使用createFiltered方法创建一个新的过滤列表。createFiltered函数在列表的输入项上创建一个过滤的投影。

它是如何工作的

让我们演示一下 ListView 控件中的过滤功能。

Create a new Universal Windows app in Visual Studio 2015 using the JavaScript template.   Open the default.html page from the Solution Explorer and replace it with the following code.

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8" />

<title>Recipe4.4</title>

<!-- WinJS references -->

<link href="WinJS/css/ui-light.css" rel="stylesheet" />

<script src="WinJS/js/base.js"></script>

<script src="WinJS/js/ui.js"></script>

<!-- Recipe4.4 references -->

<link href="/css/default.css" rel="stylesheet" />

<script src="/js/default.js"></script>

<script src="/js/data.js"></script>

</head>

<body class="win-type-body">

<h1>Recipe4.4</h1>

<div>

<input id="txtSearch" />

</div>

<div id="template" data-win-control="WinJS.Binding.Template">

<h3 data-win-bind="innerText:name"></h3>

</div>

<div id="lstEmployees" data-win-control="WinJS.UI.ListView"

data-win-options="{itemTemplate:select('#template')}">

</div>

</body>

</html>

注意包含了设置数据源和执行过滤操作的data.js文件。这个 HTML 页面包含一个 id 为txtSearch的简单文本框和一个 ListView 控件。ListView 有一个关联的自定义模板,用于以格式化的方式显示数据。

让我们将 JavaScript 文件添加到项目的js文件夹中,并将其命名为 data.js。

(function () {

"use strict";

// List of Employees to be used a datasource.

var lstEmployees = new WinJS.Binding.List([

{ id: 1, name: "Senthil Kumar" },

{ id: 2, name: "Lohith GN" },

{ id: 3, name: "Senthil Kumar B" },

{ id: 4, name: "Vidyasagar" },

]);

function Initialize() {

WinJS.UI.processAll().done(function () {

// Get the Listview from the DOM

var lstControl = document.getElementById('lstEmployees').winControl;

// Get the Search Tex from the HTML Page

var filterText = document.getElementById('txtSearch');

lstControl.itemDataSource = lstEmployees.dataSource;

filterText.addEventListener("keyup", function () {

filterEmployee(lstControl, filterText.value);

});

});

}

// Function to filter the list

function filterEmployee(listEmployee,searchtext)

{

var filtereddata = lstEmployees.createFiltered(function (item) {

var result = item.name.toLowerCase().indexOf(searchtext);

return item.name.toLowerCase().indexOf(searchtext) == 0;

});

listEmployee.itemDataSource = filtereddata.dataSource;

}

document.addEventListener("DOMContentLoaded", Initialize);

})();

这段 JavaScript 代码包含一个名为filterEmployee的方法,它接受一个 ListView 控件和一个用于过滤的搜索字符串。该函数过滤 ListView 并显示与搜索字符串匹配的雇员。

下面是createFiltered方法中过滤 ListView 控件中数据源的函数。

var fileteredData = lstEmployees.createFiltered(function (item) {

var result = item.name.toLowerCase().indexOf(searchtext);

return item.name.toLowerCase().indexOf(searchtext) == 0;

});

该函数的作用类似于一个动态过滤器,当项目以搜索文本字符串开始时返回项目。

在 Windows 上运行应用。您应该会看到如图 4-7 所示的屏幕。

A978-1-4842-0719-2_4_Fig7_HTML.jpg

图 4-7。

Filtering the ListView

当您开始在文本框中输入文本时,您会看到筛选出的项目显示在屏幕上。

4.5 ListView 控件中的分组项目

问题

您需要在 ListView 中按类别对项目进行分组,而不是按平面列表进行分组。

解决办法

若要对 ListView 中的项目进行分组,需要使用分组的数据源。这可以通过使用 WinJS 中的WinJS.Binding.List.createGrouped()函数来实现。

它是如何工作的

要在 WinJS 中对 ListView 控件中的项目进行分组,有必要包含两个模板:一个用于组标题,一个用于单个项目。

让我们在 Visual Studio 2015 中创建新的 Windows Universal 项目,打开default.html页面。用下面的代码片段替换它。

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8" />

<title>Recipe4.5</title>

<!-- WinJS references -->

<link href="WinJS/css/ui-light.css" rel="stylesheet" />

<script src="WinJS/js/base.js"></script>

<script src="WinJS/js/ui.js"></script>

<!-- Recipe4.5 references -->

<link href="/css/default.css" rel="stylesheet" />

<script src="/js/default.js"></script>

<script src="/js/data.js"></script>

</head>

<body class="win-type-body">

<h1>Recipe 4.5</h1>

<div id="GroupHeader" data-win-control="WinJS.Binding.Template">

<h3 data-win-bind="innerText: technology"></h3>

</div>

<div id="employee" data-win-control="WinJS.Binding.Template">

<h4 data-win-bind="innerText:name"></h4>

</div>

<div id="lvEmployees" data-win-control="WinJS.UI.ListView"

data-win-options="{

itemTemplate: select('#employee'),

groupHeaderTemplate: select('#GroupHeader')

}">

</div>

</body>

</html>

这个代码片段包含一个名为 lvEmployees 的 ListView 控件,它有一个组头模板和与之相关联的itemTemplate

注意对data.js JavaScript 文件的引用。

让我们在 Visual Studio 2015 解决方案资源管理器中的js文件夹下创建一个新的 JavaScript 文件,并将其命名为 data.js。

(function () {

"use strict";

function Initialize() {

WinJS.UI.processAll().done(function () {

var listView1 = document.getElementById("lvEmployees").winControl;

var employeeList = new WinJS.Binding.List([

{ id: 1, name: "Senthil Kumar", technology: "Mobile" },

{ id: 2, name: "Michael", technology: "Web" },

{ id: 3, name: "Lohith", technology: "Web" },

{ id: 4, name: "Stephen", technology: "Mobile" },

{ id: 5, name: "Vidyasagar", technology: "Game" },

{ id: 6, name: "Joseph", technology: "Mobile" },

]);

var groupedEmployees = employeeList.createGrouped(

function (item) {

return item.technology;

},

function (item) {

return { technology: item.technology }

},

function (group1, group2) {

return group1 > group2 ? 1 : -1;

});

listView1.groupDataSource = groupedEmployees.groups.dataSource;

listView1.itemDataSource = groupedEmployees.dataSource;

});

}

document.addEventListener("DOMContentLoaded", Initialize);

})();

这段 JavaScript 代码创建了项目数据源和分组数据源。该列表包含雇员记录,每一项都包含属性 id、姓名和技术。

分组的数据源是使用 WinJS 的createGrouped方法创建的,该方法需要传递三个函数作为参数。

  • GroupKey:该功能用于将列表中的每一项与一个组相关联。前面的示例返回了与每个雇员相关联的技术属性。
  • GroupData:该函数返回组头显示的数据项。在前面的示例中,GroupData返回标题中显示的组的技术。
  • GroupSorter:该函数处理组的顺序;例如,以升序在标题中列出组。

请注意,分组的数据源是活动的,它也可以使用筛选的数据源。

准备好项目数据源和分组数据源后,它们分别被设置为 ListView 的groupDataSource属性和itemDataSource属性,如下所示。

listView1.groupDataSource = groupedEmployees.groups.dataSource;

listView1.itemDataSource = groupedEmployees.dataSource;

当您在 Windows 上运行应用时,您应该会看到如图 4-8 所示的屏幕。

A978-1-4842-0719-2_4_Fig8_HTML.jpg

图 4-8。

ListView with grouped data

请注意,这些项目是按技术分组的,并显示在页面上。

4.6 ListView 中的语义缩放

问题

当使用 ListView 时,您希望为用户提供一个选项,以两种不同的缩放级别查看数据。

解决办法

您可以使用 WinJS 中的 SemanticZoom 控件在您的应用中引入语义缩放功能。SemanticZoom 控件使您能够在使用 ListView 时提供同一数据的两种不同视图。

您可以通过将div元素的data-win-control属性设置为 WinJS 来添加 SemanticZoom。UI.SemanticZoom 值

它是如何工作的

语义缩放可以使用 WinJS 中的 Semantic zoom 控件实现。设想这样一个场景,您有一个员工列表,可以根据他们所使用的技术对其进行分组。为了让用户能够轻松地在技术之间导航,您可以使用语义缩放,默认情况下,您可以看到按类别分组的员工,缩小后,您只能看到技术列表。

在 Visual Studio 2015 中创建新的通用 Windows 应用,打开default.html页面。用下面提供的代码替换现有的代码。

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8" />

<title>Recipe4.6</title>

<!-- WinJS references -->

<link href="WinJS/css/ui-light.css" rel="stylesheet" />

<script src="WinJS/js/base.js"></script>

<script src="WinJS/js/ui.js"></script>

<!-- Recipe4.6 references -->

<link href="/css/default.css" rel="stylesheet" />

<script src="/js/default.js"></script>

<script src="/js/data.js"></script>

</head>

<body class="win-type-body">

<h1>Recipe 4.6</h1>

<!-- Zoom In-->

<div id="GroupHeader" data-win-control="WinJS.Binding.Template">

<h1 data-win-bind="innerText: technology"></h1>

</div>

<div id="EmployeeTemplate" data-win-control="WinJS.Binding.Template">

<h2 data-win-bind="innerText:name"></h2>

</div>

<!-- Zoom out-->

<div id="TechnologyTemplate" data-win-control="WinJS.Binding.Template">

<h6 data-win-bind="innerText: technology"></h6>

</div>

<div id="szEmployee" data-win-control="WinJS.UI.SemanticZoom">

<!-- Zoom In-->

<div id="lvEmployees" data-win-control="WinJS.UI.ListView"

data-win-options="{

itemTemplate: select('#EmployeeTemplate'),

groupHeaderTemplate: select('#GroupHeader')

}">

</div>

<!-- Zoom Out-->

<div id="lvTechnologies" data-win-control="WinJS.UI.ListView"

data-win-options="{

itemTemplate: select('#TechnologyTemplate')

}">

</div>

</div>

</body>

</html>

上一页包含一个 SemanticZoom 控件,该控件有两个 ListView 控件。下面是使用 SemanticZoom 控件和 ListView 的代码。

<div id="szEmployee" data-win-control="WinJS.UI.SemanticZoom">

<!-- Zoom In-->

<div id="lvEmployees" data-win-control="WinJS.UI.ListView"

data-win-options="{

itemTemplate: select('#EmployeeTemplate'),

groupHeaderTemplate: select('#GroupHeader')

}">

</div>

<!-- Zoom Out-->

<div id="lvTechnologies" data-win-control="WinJS.UI.ListView"

data-win-options="{

itemTemplate: select('#TechnologyTemplate')

}">

</div>

</div>

SemanticZoom 控件包括两个具有不同缩放级别的 ListView 控件。当用户试图放大或缩小时,ListView 控件会相应地切换。

让我们在项目中的js文件夹下添加一个新的 JavaScript 文件,并将其命名为 data.js。将以下代码添加到data.js文件中。

(function () {

"use strict";

function Initialize() {

WinJS.UI.processAll().done(function () {

var listView1 = document.getElementById("lvEmployees").winControl;

var listView2 = document.getElementById("lvTechnologies").winControl;

var employeeList = new WinJS.Binding.List([

{ id: 1, name: "Senthil Kumar", technology: "Mobile" },

{ id: 2, name: "Michael", technology: "Web" },

{ id: 3, name: "Lohith", technology: "Web" },

{ id: 4, name: "Stephen", technology: "Mobile" },

{ id: 5, name: "Vidyasagar", technology: "Game" },

{ id: 6, name: "Joseph", technology: "Mobile" },

]);

// Grouped Datasource

var groupedEmployees = employeeList.createGrouped(

function (item) {

return item.technology;

},

function (item) {

return { technology: item.technology }

},

function (group1, group2) {

return group1 > group2 ? 1 : -1;

});

listView1.groupDataSource = groupedEmployees.groups.dataSource;

listView1.itemDataSource = groupedEmployees.dataSource;

listView2.itemDataSource = groupedEmployees.groups.dataSource;

});

}

document.addEventListener("DOMContentLoaded", Initialize);

})();

当您运行应用时,您应该会看到如图 4-9 所示的屏幕。

A978-1-4842-0719-2_4_Fig9_HTML.jpg

图 4-9。

SemanticZoom in the default view

单击屏幕右上角显示的–按钮,或使用拉伸手势缩小。

替代视图如图 4-10 所示。

A978-1-4842-0719-2_4_Fig10_HTML.jpg

图 4-10。

Alternate ListView shown using SemanticZoom

4.7 使用 AppBar 控件

问题

您需要提供对与当前页面或当前选择相关的常见任务的快速访问。

解决办法

通过向页面添加应用栏,您可以快速访问与当前页面或当前选择相关的常见任务。通过为div元素设置data-win-control="WinJS.UI.AppBar"属性,可以将 AppBar 控件添加到页面中。

它是如何工作的

应用栏是一行,包含图标按钮和应用屏幕底部的省略号。当用户点击省略号时,它显示可用的带标签的图标按钮和菜单项。

下面是将 AppBar 控件添加到 HTML 页面的语法。

<div data-win-control="WinJS.UI.AppBar"></div>

可以使用 JavaScript 代码以及以下语法添加 AppBar 控件。

var object = new WinJS.UI.AppBar(element, options);

AppBar 命令被添加到 app bar 中。这只是显示在应用栏中的命令或按钮。

<button data-win-control="WinJS.UI.AppBarCommand"></button>

通过将控件的data-win-options属性的 section 属性设置为 secondary,可以指定 AppBarCommand 是否应显示为菜单。

让我们创建一个演示 AppBar 功能的应用,它包括以下功能。

  • 演示添加和删除选项的命令(按钮)。
  • appbar 命令(菜单项)演示当用户点击省略号时显示的菜单项。

当用户点击按钮或菜单项时,相应的事件被处理,并显示适当的消息。

在 Visual Studio 2015 中创建新的通用 Windows 项目,打开default.html页面。用下面的代码替换它的内容。

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8" />

<title>Recipe4.7</title>

<!-- WinJS references -->

<link href="WinJS/css/ui-light.css" rel="stylesheet" />

<script src="WinJS/js/base.js"></script>

<script src="WinJS/js/ui.js"></script>

<!-- Recipe4.7 references -->

<link href="/css/default.css" rel="stylesheet" />

<script src="/js/default.js"></script>

<script src="/js/appbarevents.js"></script>

</head>

<body class="win-type-body">

<div id="appBar" data-win-control="WinJS.UI.AppBar">

<button data-win-control="WinJS.UI.AppBarCommand"

data-win-options="{id:'cmdAdd', label:'Add', icon:'add', section:'primary', tooltip:'Add'}"></button>

<button data-win-control="WinJS.UI.AppBarCommand"

data-win-options="{id:'cmdRemove', label:'Remove', icon:'remove', section:'primary', tooltip:'Remove'}"></button>

<button data-win-control="WinJS.UI.AppBarCommand"

data-win-options="{id:'cmdCamera', label:'Click Photo', icon:'camera', section:'secondary', tooltip:'click'}"></button>

</div>

<div id="Message"></div>

</body>

</html>

HTML 标记在主要部分添加了两个 appbar command(Add,Remove ),在次级菜单中添加了一个 AppBarCommand (Camera)。属性为控件提供了额外的选项。其中一些属性包括以下内容:

  • Id:唯一标识 AppBarCommand。
  • label:appbar command 中显示的内容。
  • icon:appbar command 的内置图标。
  • section:app bar 中应该显示命令的部分。该值可以是主要的或次要的。
  • tooltip:鼠标悬停在命令按钮上时显示的文本。

注意,该页面包含对appbarevents.js JavaScript 文件的引用。这包含处理 appbar 命令上的事件的逻辑。让我们在项目中的js文件夹下创建一个新的 JavaScript 文件,并将其命名为 appbarevents.js。

(function () {

"use strict";

WinJS.UI.Pages.define("default.html", {

ready: function (element, options) {

element.querySelector("#cmdAdd").addEventListener("click", AddMethod, false);

element.querySelector("#cmdRemove").addEventListener("click", RemoveMethod, false);

element.querySelector("#cmdCamera").addEventListener("click", CameraMethod, false);

}

});

// Command button functions

function AddMethod() {

var message = new Windows.UI.Popups.MessageDialog("Add Button Pressed");

message.showAsync();

}

function RemoveMethod() {

var message = new Windows.UI.Popups.MessageDialog("Remove button pressed");

message.showAsync();

}

function CameraMethod() {

var message = new Windows.UI.Popups.MessageDialog("Camera button pressed");

message.showAsync();

}

})();

前面的 JavaScript 代码处理 AppBarCommand 按钮的 click 事件。单击该按钮时,会显示一条消息。

在 Windows 上运行应用。您应该会看到如图 4-11 所示的屏幕。

A978-1-4842-0719-2_4_Fig11_HTML.jpg

图 4-11。

Windows app with the AppBar

点击应用栏中的省略号按钮,显示第二部分,如图 4-12 所示。

A978-1-4842-0719-2_4_Fig12_HTML.jpg

图 4-12。

Windows app with the AppBar and secondary section

当您单击菜单按钮时,它会显示相应的消息。

4.8 使用工具栏控件

问题

您需要显示一组可以出现在任何位置的命令;例如,屏幕顶部的弹出按钮或应用栏。

解决办法

您可以使用工具栏控件在操作区域中显示尽可能多的命令。这种控制不局限于应用中的单一位置。它可以在拆分视图、弹出按钮等中找到。

它是如何工作的

使用 JavaScript 模板在 Visual Studio 2015 中创建新的通用 Windows 应用。打开default.html页面。

用下面的代码替换default.html页面的内容。

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8" />

<title>Recipe4.8</title>

<!-- WinJS references -->

<link href="WinJS/css/ui-light.css" rel="stylesheet" />

<script src="WinJS/js/base.js"></script>

<script src="WinJS/js/ui.js"></script>

<!-- Recipe4.8 references -->

<link href="/css/default.css" rel="stylesheet" />

<script src="/js/default.js"></script>

</head>

<body class="win-type-body">

<div class="basicToolbar" data-win-control="WinJS.UI.ToolBar">

<!-- Primary commands -->

<button data-win-control="WinJS.UI.Command" data-win-options="{

id:'cmdAdd',

label:'add',

section:'primary',

type:'button',

icon: 'add',

onclick: recipes.clickcommand}"></button>

<button data-win-control="WinJS.UI.Command" data-win-options="{

id:'cmdEdit',

label:'Edit',

section:'primary',

type:'button',

icon: 'edit',

onclick: recipes.clickcommand}"></button>

<button data-win-control="WinJS.UI.Command" data-win-options="{

id:'cmdDelete',

label:'delete',

section:'primary',

type:'button',

icon: 'delete',

onclick: recipes.clickcommand}"></button>

<!-- Secondary command -->

<button data-win-control="WinJS.UI.Command" data-win-options="{

id:'cmdShare',

label:'share',

section:'secondary',

type:'button',

onclick: recipes.clickcommand}"></button>

</div>

</body>

</html>

前面的代码片段在主命令中添加了三个按钮,在辅助命令中添加了一个按钮(Share)。默认情况下,辅助命令是隐藏的,当您点击省略号按钮时会显示出来。

通过将div元素的data-win-control属性设置为 WinJS 来添加工具栏控件。工具栏值。

您可以通过设置 WinJS 的data-win-control属性在工具栏中添加按钮。UI .命令值。data-win-options属性用于设置命令属性。以下是为该命令设置的一些属性。

  • id:定义命令的标识符。
  • label:定义命令显示的文本。
  • section:定义工具栏中命令应该出现的区域。这可以采用主值或次值。
  • type:设置为“button”显示按钮控件。
  • onClick:触发并调用相应 JavaScript 方法的事件。
  • icon:显示命令的内置图标。

注意,我们已经为该命令设置了OnClick事件。让我们为它添加事件。

打开项目的js文件夹下的default.js文件。在args.setPromise方法之前添加以下代码。

WinJS.Namespace.define("recipes", {

clickcommand: WinJS.UI.eventHandler(function (ev) {

var command = ev.currentTarget;

if (command.winControl) {

var message = Windows.UI.Popups.MessageDialog(command.winControl.label);

message.showAsync();

}

})

});

前面的代码片段定义了名为recipe的名称空间,并添加了一个名为clickcommand的事件处理程序。这将在调用事件时显示一个 MessageDialog。

现在,让我们在 Windows 上运行应用。您应该会看到如图 4-13 所示的屏幕。

A978-1-4842-0719-2_4_Fig13_HTML.jpg

图 4-13。

Toolbar in Windows app

当您单击命令按钮时,您会看到一个消息对话框,描述所单击的按钮。

五、数据绑定和导航

通常,当您查看任何应用时,它都是由用户界面(UI)和底层业务逻辑组成的。数据绑定是一个连接应用 UI 和业务逻辑的过程。当数据更改其值时,绑定到数据的元素会自动反映这些更改,并且当元素值更改时,底层数据也会更新并反映这些更改。

5.1 数据绑定到简单对象

问题

作为应用业务逻辑的一部分,您有一个带有数据属性的简单业务对象。您希望将业务对象的数据属性绑定到 UI 上的 HTML 元素。

解决办法

数据绑定由WinJS.Binding名称空间提供。它提供了processAll()方法,将对象的值绑定到任何 DOM 元素的值。DOM 元素必须使用data-win-bind属性,并提供需要绑定的属性名。

它是如何工作的

让我们看看如何在您的应用中执行简单的数据绑定。

Open Visual Studio 2015. Select File ➤ New Project ➤ JavaScript ➤ Windows ➤ Universal ➤ Blank App (Universal Windows) template (see Figure 5-1).

A978-1-4842-0719-2_5_Fig1_HTML.jpg

图 5-1。

New Project dialog Visual Studio creates the Universal Windows Apps blank project with all the necessary files added to the solution.   Open default.js, which is found under the js folder. Add the following lines of code inside the immediately invoked function, just after the 'use strict' directive: (function () {         "use strict";         //create a person object var person = {                 name: "John Doe",                 age: 36,                 designation: "Technical Evangelist",                 city: "Boston",         };         var app = WinJS.Application;         var activation = Windows.ApplicationModel.Activation;         app.onactivated = function (args) {                 if (args.detail.kind === activation.ActivationKind.launch) {                         if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {                         } else {                         }                         args.setPromise(WinJS.UI.processAll());                 }         };         app.oncheckpoint = function (args) {         };         app.start(); })(); Let’s bind the Person object to a div element in the HTML.   Open default.html, which is found in the root of the project. Replace the contents of <body> with the following: <div id="container">      <h3>Name:</h3>      <h2><span data-win-bind="innerText: name"></span></h2>      <h3>Age:</h3>      <h2><span data-win-bind="innerText: age"></span></h2>      <h3>Designation:</h3>      <h2><span data-win-bind="innerText: designation"></span></h2>     <h3>City:</h3>       <h2><span data-win-bind="innerText: city"></span> </h2> </div> You have a span element and you have a defined data-win-bind attribute for data binding. You are binding the innerText property of the span element with data property of the Person object you created in default.js.   Next, you need to modify the onactivated function and add the data binding call. Modify app.onactivated, as shown here: app.onactivated = function (args) {         if (args.detail.kind === activation.ActivationKind.launch) {             if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {                 // TODO: This application has been newly launched. Initialize                 // your application here.             } else {                 // TODO: This application has been reactivated from suspension.                 // Restore application state here.             }             var container = document.querySelector('#container');             var prmise = WinJS.UI.processAll().then(function () {                 WinJS.Binding.processAll(container, person)             })             args.setPromise(prmise);         }       };   Build and run the app by pressing F5 in Visual Studio. Figure 5-2 shows the output on a Windows Mobile screen.

A978-1-4842-0719-2_5_Fig2_HTML.jpg

图 5-2。

Snapshot of Windows Mobile output

如您所见,Person 对象的值(在default.js中定义)被绑定到 HTML 元素。这是可能的,因为有了WinJS.Binding名称空间。如果您还记得,您在 onactivated 函数中调用了WinJS.Binding.processAll()方法。processAll()方法将对象的值绑定到具有data-win-bind属性的 DOM 元素的值。在演示代码中,您已经在输出姓名、年龄、头衔和城市信息的div元素上设置了data-win-bind属性。

5.2 DOM 元素的数据绑定样式属性

问题

HTML 元素可以使用 CSS 定义来设置样式。在运行时,样式属性需要绑定到底层业务对象数据属性的数据属性。

解决办法

除了提供对 DOM 元素属性的数据绑定,WinJS 数据绑定框架还提供了绑定 DOM 元素样式属性的选项。样式属性可以在data-win-bind属性中绑定到绑定对象的数据属性。

它是如何工作的

Open Visual Studio 2015. Select File ➤ New Project ➤ JavaScript ➤ Windows ➤ Universal ➤ Blank App (Universal Windows) template. This creates a Universal Windows app template (see Figure 5-3).

A978-1-4842-0719-2_5_Fig3_HTML.jpg

图 5-3。

New Project dialog   Open default.js in the js folder. Add the following code inside the immediately invoked function after the 'use strict' directive: (function () {     "use strict";     //create person object     var person = {         name: "John Doe",         age: 36,         designation: "Technical Evangelist",         city: "Boston",         favcolor: "orange"     };     //Other app set-up code })(); You have added a favcolor property to the Person object. Let’s bind the favcolor to a div element’s background-color style property.   Open default.html, which is found in the root of the project. Replace the <body> content with the following: <h1>Data Bind Attributes</h1>     <br />     <div id="container">         <h3>Name:</h3>         <h2><span data-win-bind="innerText: name"></span></h2>         <h3>Age:</h3>         <h2><span data-win-bind="innerText: age"></span></h2>         <h3>Designation:</h3>         <h2><span data-win-bind="innerText: designation"></span></h2>         <h3>City:</h3>         <h2><span data-win-bind="innerText: city"></span> </h2>         <h3>Fav Color:</h3>         <div data-win-bind="style.background: favcolor" >             <div class="favcolor" data-win-bind="innerText: favcolor"></div>         </div>     </div>   Go back to the default.js file again. Modify the onactivated method as follows: app.onactivated = function (args) {         if (args.detail.kind === activation.ActivationKind.launch) {             if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {                 // TODO: This application has been newly launched. Initialize                 // your application here.             } else {                 // TODO: This application has been reactivated from suspension.                 // Restore application state here.             }             var container = document.querySelector("#container");             var prmise = WinJS.UI.processAll().then(function () {                 WinJS.Binding.processAll(container, person)             })             args.setPromise(prmise);         }     }; You just call the WinJS Binding processAll() as usual on the container that needs to be data bound.   Next, build and run the app by pressing F5 in Visual Studio. The output on a Windows Mobile screen is shown in Figure 5-4.

A978-1-4842-0719-2_5_Fig4_HTML.jpg

图 5-4。

Snapshot of Windows Mobile output

5.3 使用模板进行数据绑定

问题

简单数据绑定一次只能绑定到一个数据项。当您有一个数据项列表时,简单的数据绑定方法是不够的。

解决办法

使用简单数据绑定,您可以将一个数据项绑定到一个 DOM 元素,该元素显示数据属性的值。为了使用项目列表并允许用户更改他们想要查看的数据项,您需要一个模板。数据模板充当蓝图,在运行时,它绑定到所提供的数据项,并在指定的 DOM 元素上呈现标记。

它是如何工作的

Open Visual Studio 2015. Select File ➤ New Project ➤ JavaScript ➤ Windows Universal ➤ Blank App (Universal Windows) template. This creates a Universal Windows app template (see Figure 5-5).

A978-1-4842-0719-2_5_Fig5_HTML.jpg

图 5-5。

New Project dialog   Open default.js in js folder. Inside the immediately invoked function, let’s declare a Person object with a couple of properties. This time you will use WinJS.Binding.define to declare the Person object. Using define will make all the properties bindable. Here is the code snippet for a Person object: (function () {     "use strict";     var Person = WinJS.Binding.define({         name: "",         color: "",         birthday: "",         petname:"",         dessert:""     });     //other app code ... })();   Open default.html, found in root of the project. Replace the content of the <body> tag with the following code: <h1>Data Binding Template</h1> <div id="templateDiv" data-win-control="WinJS.Binding.Template">     <div class="templateItem" data-win-bind="style.background: color" style="color:white">         <ol>             <li><span>Name :</span><span data-win-bind="textContent: name"></span></li>             <li><span>Birthday:</span><span data-win-bind="textContent: birthday"></span></li>             <li><span>Pet's name: </span><span data-win-bind="textContent: petname"></span></li>             <li><span>Dessert: </span><span data-win-bind="textContent: dessert"></span></li>         </ol>     </div> </div> <div id="renderDiv"></div> You have defined a div with the id templateDiv and then added a data-win-control attribute with a WinJS.Binding.Template value. This defines the template that can be used for data binding. You then have a div with the id renderDiv. At runtime, you data bind the template with data and render the output to the renderDiv DOM element.   For the purpose of this recipe, let’s create three Person objects and add a drop-down list so that you can select the person whose details needs to be shown. Inside the body tag, add the following code right after the "renderDiv" element: <fieldset id="templateControlObject">     <legend>Pick a name:</legend>     <select id="templateControlObjectSelector">         <option value="0">Show John Doe</option>         <option value="1">Show Jane Dow</option>         <option value="2">Show Jake Doe</option>     </select> </fieldset>   Back in default.js file, right after the Person object definition, create an array of three Person objects, as follows: (function () {     "use strict";     var Person = WinJS.Binding.define({         name: "",         color: "",         birthday: "",         petname:"",         dessert:""     })     var people = [         new Person({ name: "John Doe", color: "red", birthday: "2/2/2002", petname: "Spot", dessert: "chocolate cake" }),         new Person({ name: "Jane Doe", color: "green", birthday: "3/3/2003", petname: "Xena", dessert: "cherry pie" }),         new Person({ name: "Jake Doe", color: "blue", birthday: "2/2/2002", petname: "Pablo", dessert: "ice cream" }),     ];     //Other app code ... })();   Next, add a listener to the change event of the drop-down list in the onactivated method in default.js. Here is the code snippet: app.onactivated = function (args) {     // Other activation code ...     var selector = document.querySelector("#templateControlObjectSelector");           selector.addEventListener("change", handleChange, false);     args.setPromise(WinJS.UI.processAll()); }   Let’s create the event handler for the drop-down list change event. Select the div, which contains the template and the div where you want to render the markup. Call render on the template control. Create a handleChange function in default.js with the following code: (function () {     //Other app code...     function handleChange(evt) {         var templateElement = document.querySelector("#templateDiv");         var renderElement = document.querySelector("#renderDiv");         renderElement.innerHTML = "";         var selected = evt.target.selectedIndex;         var templateControl = templateElement.winControl;         templateElement.winControl.render(people[selected], renderElement);     } })();   Build and run the app by pressing F5 in Visual Studio. When you select an item in the drop-down list, the appropriate data is shown in the div above it. Figure 5-6 shows the output on a Windows Mobile screen.

A978-1-4842-0719-2_5_Fig6_HTML.jpg

图 5-6。

Data binding template output on Windows Mobile screen

5.4 数据绑定 WinJS 控件

问题

您有一个项目列表,您希望将该列表数据绑定到一个 WinJS 控件,如 ListView。

解决办法

使用 WinJS 数据绑定,您可以将任何 WinJS 控件绑定到数据源。为了显示每个单独的项目,您将提供一个数据模板。在运行时,列表获取绑定到控件的数据,并且根据定义的模板呈现每一项。

它是如何工作的

Open Visual Studio 2015. Select File ➤ New Project ➤ JavaScript ➤ Windows ➤ Universal ➤ Blank App (Universal Windows) template. This creates a Universal Windows app template (see Figure 5-7).

A978-1-4842-0719-2_5_Fig7_HTML.jpg

图 5-7。

New Project dialog   Let’s create a new JavaScript file that will provide data to the ListView. Right-click the js folder. Select Add ➤ New Item. In the New Item dialog, select the JavaScript file and name it data.js. Add the following code to the data.js file: (function () {     var flavors = [         { title: "Basic banana", text: "Low-fat frozen yogurt" },         { title: "Banana blast", text: "Ice cream" },         { title: "Brilliant banana", text: "Frozen custard" },         { title: "Orange surprise", text: "Sherbet" },         { title: "Original orange", text: "Sherbet" },         { title: "Vanilla", text: "Ice cream" },         { title: "Very vanilla", text: "Frozen custard" },         { title: "Marvelous mint", text: "Gelato" },         { title: "Succulent strawberry", text: "Sorbet" }     ];     var flavorList = new WinJS.Binding.List(flavors);     WinJS.Namespace.define("DataExample", {         flavorList: flavorList     }); })();   Add a reference to the data.js file in your default.html, which is found at the root of the project. <head>     <!-- Other file references ... -->     <!-- Your data file. -->     <script src="/js/data.js"></script> </head>   In default.html, you will now create a ListView and bind it to the data source you have created in the data.js file. Also define an item template for the list view items. Add the following code to default.html. <h1>ListView Data Binding</h1> <div id="flavorItemTemplate" data-win-control="WinJS.Binding.Template">     <div id="templateContainer">         <div id="itemContainer">             <h4 data-win-bind="innerText: title"></h4>             <h6 data-win-bind="innerText: text"></h6>         </div>     </div> </div> <div id="basicListView" data-win-control="WinJS.UI.ListView"      data-win-options="{itemDataSource : DataExample.flavorList.dataSource,                         itemTemplate:select('#flavorItemTemplate'),                         selectionMode: 'none',                         layout:{type:WinJS.UI.ListLayout}}"> </div> Create the list view by setting the data-win-control attribute with a WinJS.UI.ListView value. Use the data-win-options attribute to set control options like item data source, item template, and the layout of the list view.   Next, you need to add a little bit of style to the list view and the list view items. Open default.css in Windows and Windows Mobile projects, and add the following style sheet definition: #basicListView{     height: 100%;     margin-top: 10px;     margin-right: 20px; } #templateContainer{     display: -ms-grid;     -ms-grid-columns: 1fr;     min-height: 150px; } #itemContainer{     background-color:lightgray;     width:100%;     padding:10px; }   Build and run the app by pressing F5 in Visual Studio. Figure 5-8 shows the output on a Windows Mobile screen.

A978-1-4842-0719-2_5_Fig8_HTML.jpg

图 5-8。

ListView Data Binding Output on a Windows Mobile Screen

5.5 应用中的导航结构

问题

你想把你的应用分成多个页面/屏幕来处理特定的功能。您想知道应该遵循什么样的导航结构来提供在页面/屏幕之间移动的最佳体验。

解决办法

现实世界中的应用很少只有一个页面/屏幕,而是由许多页面/屏幕组成。每个页面/屏幕负责一个特定的功能。最好是将你的应用分成不同的功能,并分配一个专门的页面/屏幕来处理这些功能。UWP 应用中的导航基于导航结构、元素和系统级功能。通过在应用中提供正确的导航,您可以实现从一个页面到另一个页面或从这个内容到那个内容的直观用户体验。

应用中的每个页面都将包含或满足一组特定的内容或功能。例如,联系人管理应用会有一个列出联系人的屏幕、一个创建联系人的屏幕、一个更新联系人的屏幕或一个删除联系人的屏幕。应用的导航结构由您如何组织应用的不同屏幕来定义。图 5-9 展示了 UWP 应用中可以采用的不同导航结构。

A978-1-4842-0719-2_5_Fig9_HTML.jpg

图 5-9。

Navigation structures

层次导航结构是一个树状结构。每个子页面只有一个父页面。要接触到孩子,你需要穿过父母。

对等是页面并排存在的导航结构。你可以以任何顺序从一页转到另一页。

组合导航结构使用层次结构和对等结构。页面组被组织成对等体或层次结构。

5.6 应用中的导航元素

问题

你了解导航结构。你想知道哪些元素可以用来实现你的应用的导航结构。

解决办法

用户可以在许多导航元素的帮助下找到他想看的内容。在某些情况下,导航元素会向用户指示内容在应用中的位置。导航元素可以用作内容或命令元素。因此,建议使用最适合您的导航结构的导航元素。以下是 UWP 应用可用的一些导航元素:

  • Pivot:该控件用于显示指向同一级别页面的持久链接列表。当您有对等导航结构时,可以使用此控件。
  • SplitView:这个控件用于显示一个应用中顶级页面的链接列表。这可以用在需要对等导航结构的场景中。
  • Hub:这个控件用于显示子页面的预览/摘要。导航到子页面是通过页面本身提供的链接或部分标题。当您具有层次导航结构时,将使用此控件。
  • ListView:这个控件用于显示项目摘要的主列表。选择一个项目会在详细信息部分显示所选项目的详细信息。这可以用于您的层次导航结构场景。

5.7 应用中的透视导航

问题

在您的应用中,您已经确定导航的导航结构是基于对等的。您希望使用透视控件实现导航。

解决办法

当您经常访问不同的内容类别时,Pivot 控件用于导航。Pivot 由两个或多个内容窗格组成,每个窗格都有一个相应的类别标题。标题将持续显示在屏幕上,选择状态清晰可见,这使得用户很容易知道他们选择了哪个类别。用户可以在标题上向左或向右滑动,这样做将允许他们导航到相邻的标题。他们还可以在内容上向左或向右滑动。

它是如何工作的

Open Visual Studio 2015. Select File ➤ New Project ➤ JavaScript ➤ Windows ➤ Universal ➤ Blank App (Windows Universal) template. This creates a Universal Windows app project (see Figure 5-10).

A978-1-4842-0719-2_5_Fig10_HTML.jpg

图 5-10。

New Project dialog   Open default.html, which is found in the root of the project. Replace the content of the body with the following content: <div data-win-control="WinJS.UI.Pivot" data-win-options="{ title: 'PIVOT Navigation', selectedIndex: 0 }">         <div data-win-control="WinJS.UI.PivotItem" data-win-options="{ 'header': 'one'}">             <p> Content - Item One </p>         </div>         <div data-win-control="WinJS.UI.PivotItem" data-win-options="{ 'header': 'two'}">             <p> Content - Item Two </p>         </div>         <div data-win-control="WinJS.UI.PivotItem" data-win-options="{ 'header': 'three'}">             <p> Content - Item Three </p>         </div>     </div> You have placed a div and set the data-win-control attribute to a value of WinJS.UI.Pivot. This converts the div to a Pivot control. You then pass options to the Pivot control using the data-win-options attribute. You are setting the title of the Pivot and the item that will be selected. The items of the pivot control are placed as a div with the data-win-control attribute set to a value of WinJS.UI.PivotItem. Each pivot item has a header. Set the header value using the data-win-options attribute. You can place as many items that your app calls for.   Next, press F5 and run the app. Figure 5-11 is a screenshot from the Windows Mobile output.

A978-1-4842-0719-2_5_Fig11_HTML.jpg

图 5-11。

Windows Mobile output

如您所见,有三个枢纽项目。您可以单击透视项目的标题,或者从左向右滑动以导航到相邻的内容/项目。

5.8 应用中的拆分视图导航

问题

在您的应用中,您已经确定导航的导航结构是基于对等的。您希望提供一个带有顶级页面链接的菜单。您希望使用 SplitView 控件实现导航。

解决办法

SplitView 控件包含一个窗格和一个内容区域。窗格可以展开或折叠,而内容区域始终可见。窗格也可以保持打开状态,并且可以灵活地从应用的左侧或右侧显示。通常,导航链接位于此窗格中。

它是如何工作的

Open Visual Studio 2015. Select File ➤ New Project ➤ JavaScript ➤ Windows ➤ Universal ➤ Blank App (Windows Universal) template. This creates a Universal Windows app project (see Figure 5-12).

A978-1-4842-0719-2_5_Fig12_HTML.jpg

图 5-12。

New Project dialog   Open default.html, which is found in the root of the project. Replace the content of the body with the following code snippet: <div id="app">         <div class="splitView"              data-win-control="WinJS.UI.SplitView"              data-win-options="{closedDisplayMode:'none',              openedDisplayMode:'overlay'}">             <!-- Pane area -->             <div>                 <div class="header">                     <button class="win-splitviewpanetoggle"                             data-win-control="WinJS.UI.SplitViewPaneToggle"                             data-win-options="{ splitView: select('.splitView') }"></button>                     <div class="title">Menu</div>                 </div>                 <div id='navBar' class="nav-commands">                     <div data-win-control="WinJS.UI.NavBarCommand"                          data-win-options="{ onclick:SplitViewHelper.homeClick,                                              label: 'Home',                                              icon: 'home'}"></div>                     <div data-win-control="WinJS.UI.NavBarCommand"                          data-win-options="{ onclick:SplitViewHelper.favClick,                                              label: 'Favorite',                                              icon: 'favorite'}"></div>                     <div data-win-control="WinJS.UI.NavBarCommand"                          data-win-options="{ onclick:SplitViewHelper.settingsClick,                                              label: 'Settings',                                              icon: 'settings'}"></div>                 </div>             </div>             <!-- Content area -->             <button class="win-splitviewpanetoggle"                     data-win-control="WinJS.UI.SplitViewPaneToggle"                     data-win-options="{ splitView: select('.splitView') }"></button>             <div class="contenttext"><h2>Page Content </h2> </div>         </div>     </div> In order to use SplitView, you need to place a div and set the data-win-control attribute to a value of SplitView. Then you need to create two divs. The first div will be used for the navigation pane and second div will be used as the content area. You use WinJS.UI.NavBarCommand to place the links for different pages. You are listening for the click event of the nav bar items and on click will show content according to the navigation link that was clicked. The content page is just a div, and at runtime, depending on the navigation link clicked, you will update the content accordingly.   Next open default.js, found in the js folder. Replace the app.activated handler with the following code snippet: app.onactivated = function (args) {                 if (args.detail.kind === activation.ActivationKind.launch) {                         if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {                         } else {                         }                         args.setPromise(                     WinJS.UI.processAll().done(function () {                         SplitViewHelper.splitView = document.querySelector(".splitView").winControl;                         new WinJS.UI._WinKeyboard(SplitViewHelper.splitView.paneElement); // Temporary workaround: Draw keyboard focus visuals on NavBarCommands                     })             );                 }         };   Next, after the IIFE (immediately invoked function expression) declaration, place the following code snippet. You are creating a small helper classto handle the navigation click event. (function () {         "use strict";         //other app related code ommitted for brevity })(); WinJS.Namespace.define("SplitViewHelper", {     splitView: null,     homeClick: WinJS.UI.eventHandler(function (ev) {         document.querySelector('.contenttext').innerHTML = "<h2>SplitView Content area</h2>";     }),     favClick: WinJS.UI.eventHandler(function (ev) {         document.querySelector('.contenttext').innerHTML = "<h2>Favorites!</h2>";     }),     settingsClick: WinJS.UI.eventHandler(function (ev) {         document.querySelector('.contenttext').innerHTML = "<h2>Settings!</h2>";     }), }); You are replacing the inner HTML of the content div in this example. If you want to load a new page altogether, you can do so by making use of WinJS.UI.Pages.render('<URI>',<Content Host Elementn>);.   Now, press F5 and run the app. Figures 5-13 and 5-14 show output on a Windows Mobile.

A978-1-4842-0719-2_5_Fig14_HTML.jpg

图 5-14。

Content area

A978-1-4842-0719-2_5_Fig13_HTML.jpg

图 5-13。

Navigation pane

5.9 UWP 应用中的枢纽导航

问题

您已经确定通用 Windows 平台应用的导航结构本质上是分层的。您希望在应用中使用 Hub 作为导航元素。

解决办法

Hub 控件用于导航,应用的内容可以分成不同的、相关的部分或类别,具有不同的详细程度。这是在诸如关系信息这样的场景中使用的一种常见模式,这种关系信息需要以优选的顺序遍历。导航的层次模式适用于提供各种体验和内容的应用。

它是如何工作的

Open Visual Studio 2015. Select File ➤ New Project ➤ JavaScript ➤ Windows ➤ Universal ➤ Blank App (Windows Universal) template. This creates a Universal Windows app project (see Figure 5-15).

A978-1-4842-0719-2_5_Fig15_HTML.jpg

图 5-15。

New Project dialog   Open default.html, found in the root of the project. Replace the contents after the <body> tag with the following code snippet: <div data-win-control="WinJS.UI.Hub">         <div class="section1" data-win-control="WinJS.UI.HubSection"              data-win-options="{header: 'Images', isHeaderStatic: true}">             <div class="imagesFlexBox">                 <img class="imageItem" src="/img/circle_image1.jpg" />                 <img class="imageItem" src="/img/circle_image3.jpg" />                 <img class="imageItem" src="/img/circle_image2.jpg" />                 <img class="imageItem" src="/img/circle_image1.jpg" />                 <img class="imageItem" src="/img/circle_image3.jpg" />                 <img class="imageItem" src="/img/circle_image2.jpg" />                 <img class="imageItem" src="/img/circle_image1.jpg" />                 <img class="imageItem" src="/img/circle_image3.jpg" />                 <img class="imageItem" src="/img/circle_image2.jpg" />             </div>         </div>         <div id="list" class="section2" data-win-control="WinJS.UI.HubSection"              data-win-options="{header: 'ListView', isHeaderStatic: true}">             <div id="listView"                  class="win-selectionstylefilled"                  data-win-control="WinJS.UI.ListView"                  data-win-options="{                 itemDataSource: HubExample.data.dataSource,                 itemTemplate: smallListIconTextTemplate,                 selectionMode: 'none',                 tapBehavior: 'none',                 swipeBehavior: 'none'             }">             </div>         </div>     </div>     <div id="smallListIconTextTemplate" data-win-control="WinJS.Binding.Template">         <div class="smallListIconTextItem">             <img src="#" class="smallListIconTextItem-Image"                  data-win-bind="src: picture" />             <div class="smallListIconTextItem-Detail">                 <h4 data-win-bind="innerText: title"></h4>                 <h6 data-win-bind="innerText: text"></h6>             </div>         </div>     </div> To create a Hub control, set the data-win-control attribute to a value of WinJS.UI.Hub on a div. To create sections inside the Hub, create a div and set its data-win-control attribute to WinJS.UI.HubSection. Set the header of the sections using the data-win-options attribute. Set the header property on the section.   Section 2 in the preceding code makes use of a ListView. So let’s create a data source for the list view. Open the default.js file in the js folder. Inside the immediately invoked function expression and after 'use strict' statement, copy and paste the following code snippet: var myData = new WinJS.Binding.List([   { title: "Fire Hydrant", text: "Red", picture: "/img/circle_list1.jpg" },   { title: "Fire Hydrant", text: "Yellow", picture: "/img/circle_list2.jpg" },   { title: "Pothole Cover", text: "Gray", picture: "/img/circle_list3.jpg" },   { title: "Sprinkler", text: "Yellow", picture: "/img/circle_list4.jpg" },   { title: "Electrical Charger", text: "Yellow", picture: "/img/circle_list5.jpg" },   { title: "Knob", text: "Red", picture: "/img/circle_list6.jpg" },   { title: "Fire Hydrant", text: "Red", picture: "/img/circle_list1.jpg" },   { title: "Fire Hydrant", text: "Yellow", picture: "/img/circle_list2.jpg" },   { title: "Pothole Cover", text: "Gray", picture: "/img/circle_list3.jpg" },   { title: "Fire Hydrant", text: "Red", picture: "/img/circle_list1.jpg" },   { title: "Fire Hydrant", text: "Yellow", picture: "/img/circle_list2.jpg" },   { title: "Pothole Cover", text: "Gray", picture: "/img/circle_list3.jpg" }   ]);         WinJS.Namespace.define("HubExample", {             data: myData         });   To run the app, press F5 in Visual Studio. Figure 5-16 shows output on a Windows Mobile device.

A978-1-4842-0719-2_5_Fig16_HTML.jpg

图 5-16。

Hub navigation output

5.10 在 UWP 应用中使用 ListView 进行主/详细信息导航

问题

您已经确定通用 Windows 平台应用的导航结构本质上是分层的。您希望使用主/详细导航模式。您已经将 ListView 标识为导航元素。

解决办法

ListView 是一个在垂直堆栈中显示数据项列表的控件。您可以将数据源数据绑定到列表视图,并为呈现每个项目提供模板。

它是如何工作的

Open Visual Studio 2015. Select File ➤ New Project ➤ JavaScript ➤ Windows ➤ Universal ➤ Blank App (Windows Universal) template. This creates a Universal Windows app project (see Figure 5-17).

A978-1-4842-0719-2_5_Fig17_HTML.jpg

图 5-17。

New Project dialog   Open default.html, which is found in the root of the project. Replace the contents of the body with the following code snippet: <h1>ListView Navigation</h1> <div id="contentHost"></div> You have a div with id contentHost. Use this as a placeholder to show different pages at runtime; that is, render the master and details page inside this content host div element.   Next, open default.js, found in the js folder. Add the following code snippet just before the app.onactivated function definition: WinJS.Navigation.addEventListener("navigating", function (args) {         var url = args.detail.location;         var host = document.getElementById("contentHost");         host.winControl && host.winControl.unload && host.winControl.unload();         WinJS.Utilities.empty(host);         args.detail.setPromise(WinJS.UI.Pages.render(url, host, args.detail.state));     }); Through this code, you are listening to a navigation event that will occur on the page. You have provided a handler for the navigation event. In the event handler, you intercept the navigation call, get the URL of the destination page, get the content host element, and render the destination page inside the content host element.   Next, modify the app.onactivated method, as follows: app.onactivated = function (args) { if (args.detail.kind === activation.ActivationKind.launch) {     if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {     } else {     }     args.setPromise( WinJS.UI.processAll().then(function () {             return WinJS.Navigation.navigate("/master.html");         })    ); }     }; The only thing done in the activated event handler is navigating to a page named master.html (you will create this page next). So when the app loads, master.html, which will hold the ListView control, will be rendered inside the content host.   Add a new HTML file to the project and name it master.html. Replace the contents of the master.html with the following snippet: <!DOCTYPE html> <html> <head>     <title></title>     <link href="/css/default.css" rel="stylesheet" />     <!-- WinJS references -->     <link href="WinJS/css/ui-dark.css" rel="stylesheet" />     <script src="WinJS/js/base.js"></script>     <script src="WinJS/js/ui.js"></script>     <script src="js/data.js"></script>     <script src="js/master.js"></script> </head> <body >     <div class="smallListIconTextTemplate"          data-win-control="WinJS.Binding.Template"          style="display: none">         <div class="smallListIconTextItem">             <img src="#" class="smallListIconTextItem-Image"                  data-win-bind="src: picture" />             <div class="smallListIconTextItem-Detail">                 <h4 class="win-h4" data-win-bind="textContent: title"></h4>                 <h6 class="win-h6" data-win-bind="textContent: text"></h6>             </div>         </div>     </div>     <div class="listView win-selectionstylefilled"          data-win-control="WinJS.UI.ListView"          data-win-options="{                     itemDataSource: ListViewExample.data.dataSource,                     itemTemplate: select('.smallListIconTextTemplate'),                     tapBehavior: WinJS.UI.TapBehavior.directSelect,                     layout: { type: WinJS.UI.ListLayout }             }">     </div> </body> </html> What you have done in master.html is place a list view, provide a data source to the list view, and provide an item template for rendering each item. The template displays an image, title, and text from the data item that will be bound at runtime.   Next, create a new JavaScript file in the js folder and name it master.js. Add the following code snippet to the JavaScript file: (function () {     'use strict';     WinJS.UI.Pages.define("/master.html", {         ready: function (element, options) {             var that = this;             element.addEventListener("iteminvoked", function (evt) {                 evt.detail.itemPromise.then(function (item) {                     WinJS.Application.sessionState.selectedItem = item.data;                     WinJS.Navigation.navigate("/detail.html");                 });             });         }     }) })(); Let’s go over the code for a moment. You have created a logic file for master.html with this new JavaScript file. Define page members with the WinJS.UI.Pages.define() method. You have provided a ready method that will be called when the page is loaded. And you are adding event listener for ListView item tap. When the item is tapped, store the selected item in an application session state and then navigate to detail.html.   Next, create a new JavaScript file named data.js inside the js folder. This file provides the data source for the ListView in master.html. Paste the following code snippet in data.js: var myData = new WinJS.Binding.List([ { title: "Lemon", text: "Sorbet", picture: "/img/60Lemon.png" }, { title: "Mint", text: "Gelato", picture: "/img/60Mint.png" }, { title: "Orange", text: "Sorbet", picture: "/img/60Orange.png" }, ]); WinJS.Namespace.define("ListViewExample", {         data : myData });   Now let’s create the details page. Add a new HTML file to the root of the project and name it detail.html. Paste the following code snippet to the newly created file: <!DOCTYPE html> <html> <head>     <title></title>     <link href="/css/default.css" rel="stylesheet" />     <!-- WinJS references -->     <link href="WinJS/css/ui-dark.css" rel="stylesheet" />     <script src="WinJS/js/base.js"></script>     <script src="WinJS/js/ui.js"></script>     <script src="/js/detail.js"></script> </head> <body>     <div>         <button data-win-control="WinJS.UI.BackButton"></button>         <h3>Item Details </h3>         <h2><span data-win-bind="innerText: title"></span></h2>         <img data-win-bind="src: picture" />         <h2><span data-win-bind="innerText: text"></span></h2>     </div> </body> </html> In this page, just output the details of the selected item in the list view. Notice that you are using data binding expressions to show the title, text, and image of the data item.   Now you need to create the logic file for detail.html. Add a new JavaScript file named detail.js inside the js folder. Paste the following code snippet to the newly created file: (function () {     'use strict';     WinJS.UI.Pages.define("/detail.html", {         processed: function (element, options) {             var that = this;             WinJS.Binding.processAll(element, WinJS.Application.sessionState.selectedItem);         }     }) })(); When the page loads, just call the Binding.processAll() on the page and provide the selected item as the data item that needs to be bound to the elements.   You are done with all the code required for master/detail navigation. Now press F5 and run the app. Figures 5-18 and 5-19 show the output from a Windows Mobile device.

A978-1-4842-0719-2_5_Fig19_HTML.jpg

图 5-19。

Details screen

A978-1-4842-0719-2_5_Fig18_HTML.jpg

图 5-18。

Master screen

六、为不同的屏幕调整用户界面

借助通用 Windows 平台(UWP),您可以在 Windows 系列的任何设备上运行您的应用。设备系列包括手机、平板电脑、笔记本电脑、Xbox 等等。设备系列中有不同的屏幕尺寸。该平台在幕后施展魔法,确保你的应用的用户界面在所有设备上都能正常工作。由于平台在幕后为你处理事情,你不需要对你的应用做任何定制来支持不同的屏幕尺寸。但是在某些情况下,您可能希望为特定的屏幕尺寸提供特定的 UI。例如,当你的应用在手机上运行时,你可能想要一个单列布局;而当同一个应用在平板电脑或个人电脑上运行时,你想要两栏布局。本章着眼于如何让你的用户界面适应不同的屏幕尺寸。

如果 UWP 应用可以在任何屏幕尺寸的任何 Windows 10 设备系列上运行,那么作为应用开发者,你为什么要担心为特定屏幕尺寸量身定制的用户界面呢?

如前所述,该平台负责确保您的应用的用户界面在所有屏幕尺寸下都能正常工作,但您可能仍然需要根据应用运行的屏幕进行定制。以下几点值得注意。它们提供了关于您为什么想要定制的见解。

  • 有效利用可用空间,减少导航。当一个应用的用户界面被设计成在小屏幕上看起来不错时,这个应用也可以在个人电脑上使用。但是可能会有一些浪费的空间。更好的设计是当屏幕尺寸超过一定尺寸时显示更多的内容。在更大的屏幕上显示更多的内容可以减少用户导航的次数。
  • 设备能力。不同的设备有不同的功能。通过为特定设备定制您的应用,您可以更好地利用该特定设备上的可用功能,然后您可以启用/禁用与此相关的功能。
  • 输入优化。UWP 中的控件库适用于所有输入类型,包括触摸、笔、键盘和鼠标。但是您可以针对特定设备优化输入。例如,基于手机的应用通常在屏幕底部提供导航;而 PC 用户期望导航在屏幕的顶部可用。

6.1 为不同屏幕设计断点

问题

由于您需要支持 Windows 10 设备系列下的各种屏幕尺寸,您可能想知道您的应用中的具体目标宽度。

解决办法

断点是 CSS(级联样式表)中使用的术语,用来表示屏幕的大小或宽度,您可以根据它来编写样式规则。Windows 10 设备系列中有大量设备目标和屏幕尺寸可用。但是您不必针对这些设备目标或屏幕尺寸中的每一个来优化您的 UI。相反,你应该设计关键的屏幕宽度。这些关键屏幕宽度也称为断点。让我们看看您应该关注的断点。

  • 小:320epx。这些设备目标/屏幕的有效像素宽度为 320。典型的屏幕尺寸是 4 到 6 英寸。通常,这些设备是电话。
  • 中等:720epx。这些设备目标/屏幕的有效像素宽度为 720。典型的屏幕尺寸是 6 到 12 英寸。通常,这些设备是大屏幕的平板电脑和手机。
  • 大:1024epx。这些设备目标/屏幕的有效像素宽度为 1024 或更高。典型的屏幕尺寸为 13 英寸及以上。通常,这些设备是 PC、笔记本电脑、Surface Hubs 等等。

6.2 自适应 UI 技术:重新定位

问题

您希望您的应用支持所有设备目标/屏幕尺寸。你想让你的用户界面自适应,你想根据你的应用运行的屏幕大小重新定位你的屏幕的某些部分。

解决办法

使你的应用的用户界面适应不同屏幕尺寸的技术之一涉及 CSS 媒体查询,这超出了本书的范围,因此,你不会深入研究它。但是你可以在 W3C 学校在线 http://www.w3schools.com/cssref/css3_pr_mediaquery.asp 阅读和了解更多关于媒体查询的信息。您将编写一个针对屏幕大小的媒体查询规则。该规则将定义样式,以根据应用运行的屏幕重新定位 UI 元素。

它是如何工作的

Open Visual Studio 2015. Select File ➤ New Project ➤ JavaScript ➤ Windows ➤ Universal ➤ Blank App (Universal Windows) template. This creates a universal Windows app template (see Figure 6-1).

A978-1-4842-0719-2_6_Fig1_HTML.jpg

图 6-1。

New Project dialog   Open the default.html, which is found at the root of the project. After the tag, add the following content: <div class="appGrid">         <div class="sectionA">             <h1>A</h1>         </div>         <div class="sectionB">             <h1>B</h1>         </div> </div> You have created a bunch of divs. The outer div (appGrid) acts as a container. Next, you have two sections that are displayed as part of the app. On a small screen, you want to show sectionA and sectionB one on top of the other. When running on medium and large screens, place sectionA and sectionB next to each other.   Next, you create the necessary styles for the app. Open default.css, which is found in the css folder. Replace the contents of default.css with the following style rules. .appGrid {     display: -ms-grid;     -ms-grid-columns: 2fr 1fr;     grid-columns: 2fr 1fr;     -ms-grid-rows: 1fr;     grid-rows: 1fr;     width: 100%;     height: 100%;     margin:24px; } .sectionA {     -ms-grid-row: 1;     -ms-grid-column: 1;     background-color: lightgray;     width: 100%;     height: 100%;     padding: 10px;     color: black; } .sectionB {     -ms-grid-row: 1;     -ms-grid-column: 2;     background-color: lightblue;     width: 100%;     height: 100%;     padding: 10px;     color: black; } Let’s go through the code once. You have just defined three rules. One of the rules is for the outer grid. You are using a grid-based display with two columns and one row. Section A is placed in column 1 and Section B is placed in column 2. Since there is no media query applied yet, these rules are applied all the time.   Now you define a media query for handling the UI when the max width of the screen is 320. When you are running the app on a small screen, you want the layout to be narrow—only one column and two rows. Section A is placed in row 1 and Section B is placed in row 2. You place the CSS rule in the same CSS file (default.css). Here is the code snippet for the media query: @media (max-width:320px){     .appGrid {         display: -ms-grid;         -ms-grid-columns: 1fr;         grid-columns: 1fr;         -ms-grid-rows: 2fr 1fr;         grid-rows: 2fr 1fr;         width: 100%;         height: 100%;         margin:12px;     }     .sectionA {         -ms-grid-row: 1;         -ms-grid-column: 1;         background-color: lightgray;         width: 100%;         height: 100%;     }     .sectionB {         -ms-grid-row: 2;         -ms-grid-column: 1;         background-color: lightblue;         width: 100%;         height: 100%;     } } This shows that when the screen size is 320px and lower, a new style rule is picked up. As part of the style rule, the app grid is now one column and two rows. This repositioned the placement of Section A and Section B.   Next, press F5 and run the app. You can run the app in a Windows 10 Mobile emulator or you can run it on a local machine. Figures 6-2 and 6-3 show the output from a phone and a PC.

A978-1-4842-0719-2_6_Fig3_HTML.jpg

图 6-3。

Output on a Windows PC

A978-1-4842-0719-2_6_Fig2_HTML.jpg

图 6-2。

Output on Windows Mobile

6.3 自适应 UI 技术:流畅的布局

问题

您已经创建了一个布局,希望在列表视图中显示项目的数量。但是您希望列表视图适应窄屏幕和中或大屏幕。您希望列表视图项目根据屏幕大小做出响应。

解决办法

UWP 中的 ListView 控件用于需要显示大量项目的情况。顾名思义,列表视图在屏幕上呈现一个列表,每个项目都绑定到一个数据项。列表视图的每一项都可以通过提供模板来定制。ListView 还有一个概念叫布局。布局定义了项目应该如何在屏幕上展开。它支持两种现成的布局:ListLayout 和 GridLayout。ListLayout 用于单列/多行渲染。GridLayout 呈现基于网格的布局(即行和列占据屏幕上的可用空间)。

它是如何工作的

Open Visual Studio 2015. Select File ➤ New Project ➤ JavaScript ➤ Windows Universal ➤ Blank App (Universal Windows) template. This creates a universal Windows app template (see Figure 6-4).

A978-1-4842-0719-2_6_Fig4_HTML.jpg

图 6-4。

New Project dialog   Create a new file called weatherData.js in the js folder. Add an immediately invoked function expression. Here is the code snippet: (function (undefined) {     'use strict'     //rest of the code here })();   Next, create an array of weather data after the ‘use strict’ statement inside the function body, as shown earlier. Let’s build fictitious weather data for the purpose of this recipe demo. Here is the code snippet: var weatherData = [         {             date: formatDateString(new Date().getDate()),             imgSrc: "img/tile-snow.png",             hi: "32°",             low: "16°",             temp: "24°",             feelsLike: "28°",             chanceOfSnow: "88%"         }          //add more items here         ];   Next, create a function to format the date. You want to display the date in a “Sun 10” type pattern. You need to customize the date string for display. Here is the code snippet for the formatDateString function: function formatDateString(date) {         var daysOfWeek = ["Sun","Mon","Tues","Wed","Thurs","Fri","Sat"];         var nearDays = ["Yesterday","Today","Tomorrow"];         var dayDelta = date - new Date().getDate() + 1;         var dateString = "";         if (dayDelta < 3) {             dateString = nearDays[dayDelta];         }         else {             dateString = daysOfWeek[date % 7] +             " <span class='day'>" + date + "</span>";         }         return dateString;     };   You need to expose this weatherData array so that you can consume it in default.html and bind it to the list view. Create a namespace and expose the weatherData, as shown here: var weatherDataList = new WinJS.Binding.List(weatherData); WinJS.Namespace.define("FluidApp.Data", {         weatherData : weatherDataList }) You have created a namespace called FluidApp.Data and exposed weatherData as a public property, which can be bound to any win control.   You need to add a reference to weatherData.js. Add the following script tag in head section of default.html. Add this before the default.js script file reference: <script src="/js/weatherData.js"></script>   Next, you need to create the UI. In default.html, remove the default contents, which are found inside the tag. Add the following template, which is used for displaying each item of the list view:     <div id="weatherTemplate" class="dayTemplate" data-win-     control="WinJS.Binding.Template">     <div class="dayGrid">         <div class="win-type-x-large dayDate"                     data-win-bind="innerHTML: date">         </div>         <div class="dayImg">             <img data-win-bind="src: imgSrc" />         </div>         <div class="win-type-x-large dayHighLow">             <span class="dayHigh" data-win-bind="innerHTML: hi"></span>             <span>/</span>             <span class="dayLow" data-win-bind="innerHTML: low"></span>         </div>         <div class="dayFeelsLike">             <span>Feels like </span>             <span data-win-bind="innerHTML: feelsLike"></span>         </div>         <div class="dayChanceOfSnow">             <span>Chance of snow is </span>             <span data-win-bind="innerHTML: chanceOfSnow"></span>         </div>     </div> </div>   Next, let’s add the ListView control. Paste the following code snippet after the template that you created in the previous step: <div id="weatherListView" class="weatherListView"         data-win-control="WinJS.UI.ListView"          data-win-options="{            itemDataSource:FluidApp.Data.weatherData.dataSource,            itemTemplate:select('#weatherTemplate'),           layout:WinJS.UI.GridLayout}"></div> You have created a list view and provided weatherData as the item data source. You have also provided the item template. You have set the layout of the list view to GridLayout by default. You will change this layout property of the list view based on the screen resize.   Open default.js, which is found in the js folder. Modify the app.onactivated function with the following code snippet: app.onactivated = function (args) {                 if (args.detail.kind === activation.ActivationKind.launch) {                         if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {                         } else {                         }                         args.setPromise(WinJS.UI.processAll().then(function ready() {                             var listView = document.querySelector("#weatherListView");                             var listViewLayout = new WinJS.UI.GridLayout();                             if (document.body.clientWidth <= 320) {                                 listViewLayout = new WinJS.UI.ListLayout();                             }                    listView.layout = listViewLayout;                 window.addEventListener("resize", resizeListView, false)                         }));                 }         }; Let’s go over the code here. Once the UI processing is done, you grab the list view first. You then check the width of the screen that you are currently running on. If the width is less than or equal to 320 (i.e., you are on a small screen), you just change the layout of the list view accordingly. If you are on a small screen, you use ListLayout, but when not on a small screen, you set it to GridLayout. You also register an event listener to resize the window. Next, let’s look at what the resize event handler does.   After the app.onactivated function, create a new function, resizeListView, and paste the following code snippet: function resizeListView() {     var listview = document.querySelector("#weatherListView").winControl;     if (document.body.clientWidth <= 320) {         if (!(listview.layout instanceof WinJS.UI.ListLayout)) {             listview.layout = new WinJS.UI.ListLayout();         }     }     else {         if (listview.layout instanceof WinJS.UI.ListLayout) {             listview.layout = new WinJS.UI.GridLayout();         }     } }   Now run the app on a mobile device or on a PC to see the output. Press F5 to run the app. The screenshot shown in Figure 6-5 is on Windows 10 Mobile and the one shown in Figure 6-6 is on a Windows 10 PC.

A978-1-4842-0719-2_6_Fig6_HTML.jpg

图 6-6。

Output on a Windows PC

A978-1-4842-0719-2_6_Fig5_HTML.jpg

图 6-5。

Output on a Windows 10 Mobile

你刚刚实现的是为不同屏幕尺寸量身定制的 UI。您使用了 ListView 布局技术来显示网格或列表布局,这取决于屏幕的大小。

七、应用生命周期和导航

本章介绍通用的 Windows 应用事件和生命周期,包括启动 Windows 应用时引发的标准事件集以及如何处理这些事件。本章涵盖了开发者如何处理应用的暂停和终止。它还介绍了如何在这些事件期间保存和恢复数据,这有助于开发人员提供更好的用户体验。

本章还介绍了导航模型,并解释了如何构建一个可以包含多个虚拟 HTML 页面的单页面应用。

7.1 应用状态和事件

问题

当用户启动、关闭或恢复应用时,您需要识别和订阅应用中的各种事件。

解决办法

使用通用 Windows 应用项目中的default.js文件来订阅和处理应用生命周期中的各种事件。

它是如何工作的

使用通用 Windows 模板创建一个新的通用 Windows 项目,该模板可以在 Microsoft Visual Studio 2015 的“新建项目”对话框的 JavaScript ➤ Windows ➤通用节点下找到。这将在 Visual Studio 解决方案中创建一个项目,并在其中创建必要的文件。

从项目的js文件夹中,从 Visual Studio 解决方案资源管理器中打开 default.js 文件。您会看到两个默认订阅的重要事件。

  • app.onactivated
  • app.oncheckpoint

这些事件的代码如下所示。

app.onactivated = function (args)

{

if (args.detail.kind === activation.ActivationKind.launch)

{

if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {

} else {

}

args.setPromise(WinJS.UI.processAll());

}

};

app.oncheckpoint = function (args)

{

};

作为开发人员,您应该处理这些事件来描述当各种执行状态被触发时,应用应该如何保存和恢复数据。

在通用 Windows 应用中,有三种应用执行状态:

  • 不运行
  • 运转
  • 暂停的

图 7-1 展示了通用 Windows 应用的生命周期。

A978-1-4842-0719-2_7_Fig1_HTML.jpg

图 7-1。

Application states and events

当一个通用的 Windows 应用启动时,WinJS 应用按下面显示的顺序触发以下事件。

WinJS.Application.loaded   WinJS.Application.activated   WinJS.Application.ready   WinJS.Application.unload

当你的应用将要被挂起时。Application.checkpoint 事件被触发。

表 7-1 提供了应用事件列表。

表 7-1。

List of Application Events

| 事件名称 | 描述 | | --- | --- | | WinJS。应用.已加载 | 一旦 HTML 文档被完全加载,这个事件就由`DOMContentLoaded`事件触发。 | | WinJS。应用.激活 | 当您的应用被激活时,该事件被触发。 | | WinJS。应用.就绪 | 一旦加载和激活的事件执行完成,就会触发此事件。 | | WinJS。应用.卸载 | 该事件在页面卸载前由`beforeunload`事件触发。 | | WinJS。应用.检查点 | 当应用挂起时,会触发此事件。 |

开发人员应该处理激活事件和检查点事件,以添加他们的自定义逻辑来保存和恢复应用的状态,因此,在创建新项目时,您会看到默认情况下包括这两个事件。

其他事件可以使用WinJS.Application.addEventListener方法订阅。

打开default.js文件,在onactivated事件行上方添加以下代码片段。

WinJS.Application.addEventListener("loaded", function(event) {

console.log("loaded event");

});

WinJS.Application.addEventListener("ready", function (event) {

console.log("ready event");

});

另外,在onactivated事件中添加console.log ("activated");

当您使用本地机器选项在 Windows 桌面上运行应用时,您会看到按指定顺序引发的事件,如图 7-2 所示。

A978-1-4842-0719-2_7_Fig2_HTML.jpg

图 7-2。

Application events in the JavaScript console window Note

在调用WinJS.Application.start事件之前,不会引发这些事件。这个方法在default.js文件中被调用。

Windows 应用必须首先安装在要激活的设备上。这通常可以通过从 Windows 应用商店安装应用或在开发期间使用 Visual Studio 来构建和部署通用应用来实现。

当用户从开始屏幕或应用列表中点击应用磁贴时,Windows 应用被激活。在此阶段,考虑到以下情况,应用处于未运行状态:

  • 该应用首次推出。
  • 应用没有运行,因为它崩溃了。
  • 该应用被暂停,后来被系统终止。

该应用可以通过多种方式激活。ActivationKind枚举可用于找出应用是如何激活的,并确定应用激活的确切原因。

例如,当用户点击应用磁贴时,应用可以被激活。ActivationKind 值在这种情况下启动。同样,当从搜索契约中激活应用时,会搜索 ActivationKind 值。

下面的代码片段展示了如何在onactivated事件中处理这个问题。

if (args.detail.kind === activation.ActivationKind.launch) {

console.log("launch activation kind");

}

else

if (args.detail.kind === activation.ActivationKind.Search) {

console.log("search activation kind");

}

表 7-2 显示了一些最常见的激活方法及其枚举值。

表 7-2。

Activation Methods

| 枚举成员 | 价值 | 描述 | | --- | --- | --- | | 发动 | Zero | 当用户启动应用或点击应用列表中的磁贴时,会收到该值。 | | 搜索 | one | 当用户希望使用搜索契约通过应用进行搜索时,会收到该值。 | | 共享目标 | Two | 当使用共享契约激活应用时,会收到该值。 | | 文件 | three | 当设备中的另一个应用启动一个文件时,会收到该值,该文件的文件类型由该应用注册以进行处理。 | | 草案 | four | 当另一个应用启动其方案名称被注册为由该应用处理的 URI 时,会收到该值。 | | 文件 | five | 当用户选择该应用提供的文件时,会收到该值。 | | 文件保存选择器 | six | 当用户尝试保存文件并选择应用作为位置时,会收到该值。 | | 缓存文件更新程序 | seven | 当用户尝试保存应用提供内容管理的文件时,会收到此值。 | | 联系人选取器 | eight | 该值在用户选择联系人时接收。 | | 设备 | nine | 该应用处理自动播放。 | | 语音命令 | Sixteen | 由于语音命令而激活应用时,会收到该值。 | | 祝酒词 | One thousand and ten | 当用户点击 toast 通知或 toast 通知中的操作后激活应用时,会收到该值。 |

7.2 处理应用中未处理的异常

问题

你的应用崩溃,用户立即被带到 Windows 开始屏幕,没有任何信息。您需要处理这种情况,以提供更好的用户体验。

解决办法

您可以处理default.js文件中的WinJS.Application.error事件来记录错误并向用户显示一条消息。

它是如何工作的

当您的通用 Windows 应用中出现未处理的异常时,会调用MSApp.terminateApp函数,之后应用会关闭,不会向用户提供任何信息。

在这个方法中,让我们处理WinJS.Application.error事件,并在应用中出现未处理的异常时向用户显示一条消息。

使用通用 Windows 模板创建一个新的通用 Windows 项目,该模板可以在 Microsoft Visual Studio 2015 的“新建项目”对话框的 JavaScript ➤ Windows ➤通用节点下找到。这将在 Visual Studio 解决方案中创建一个项目,并在其中创建必要的文件。

js文件夹中打开default.js文件,并用下面的代码片段替换它。

(function () {

"use strict";

var app = WinJS.Application;

var activation = Windows.ApplicationModel.Activation;

WinJS.Application.addEventListener("error", function(eventArgs) {

var errorMessage = new Windows.UI.Popups.MessageDialog("There was an error in the app. Kindly contact the app publisher");

errorMessage.showAsync();

return true;

});

app.onactivated = function (args) {

args.setPromise(WinJS.UI.processAll());

throw new WinJS.ErrorFromName();

};

app.start();

})();

这段代码从onactivated事件中抛出一个异常。WinJS.Application.addEventListener函数用于向错误事件添加一个监听器,以处理未处理的异常并向用户显示一条消息。

使用 Visual Studio 2015 中的本地计算机选项在 Windows 桌面上运行应用。您会看到图 7-3 中显示的信息。

A978-1-4842-0719-2_7_Fig3_HTML.jpg

图 7-3。

Displaying a message on an unhandled exception in the app Note

错误处理函数返回 true。值 true 用于指示错误已被处理,因此应用不应被终止。

7.3 处理应用的终止和恢复

问题

您需要确定应用以前的执行状态,以便在启动时恢复它。

解决办法

您可以使用激活事件的参数的detail.previousExecutionState属性来标识应用的状态。此属性确定应用是作为新应用启动的,还是之前被用户关闭的,或者是在应用暂停或终止后用户正在启动的。

它是如何工作的

previous ExecutionState 包含指示应用先前状态的值。您可以在激活的事件中使用该值来加载以前的状态值或基于该值的初始状态值。

使用通用 Windows 模板创建一个新的通用 Windows 项目,该模板位于 Microsoft Visual Studio 2015 中“新建项目”对话框的 JavaScript ➤ Windows ➤通用节点下。这将在 Visual Studio 解决方案中创建一个项目,并在其中创建必要的文件。

js文件夹中打开default.js文件,用下面的代码片段替换onactivated事件。

app.onactivated = function (args) {

if (args.detail.kind === activation.ActivationKind.launch) {

if (args.detail.previousExecutionState === activation.ApplicationExecutionState.notRunning) {

console.log("Previous state is not running");

}

if (args.detail.previousExecutionState === activation.ApplicationExecutionState.closedByUser) {

console.log("Previous state is closed by the user");

}

if (args.detail.previousExecutionState === activation.ApplicationExecutionState.terminated) {

console.log("Previous state is terminated");

}

args.setPromise(WinJS.UI.processAll());

}

};

这段代码处理onactivated事件,其中args.detail.previousExecutionState用于查找应用的先前状态。ApplicationExecutionState枚举用于检查应用的状态。

当您运行应用时,您会在 JavaScript 控制台窗口中看到之前显示的状态,如图 7-4 所示。

A978-1-4842-0719-2_7_Fig4_HTML.jpg

图 7-4。

PreviousExecutionState displayed in the JavaScript console window

ApplicationExecutionState 枚举包含这些值,如表 7-3 所示。

表 7-3。

ApplicationExecutionState and Enumeration Values

| 状态 | 描述 | | --- | --- | | 不运行 | 当用户第一次启动应用,关闭应用,并在 10 秒内启动应用,或者当应用崩溃时,此应用的先前状态为“未运行”。 | | 运转 | 如果应用已经在运行,并且用户使用契约或辅助磁贴启动应用,则应用的先前状态为“正在运行”。 | | 暂停的 | 如果应用被暂停,并且稍后通过辅助磁贴或合约激活,则应用的先前状态为“暂停”。 | | 终止的 | 如果应用先前被操作系统终止,则应用的先前状态为“已终止”。 | | closedByUser | 如果应用被用户关闭并且在 10 秒内没有重新启动,则应用的先前状态为“closedByUser”。可以使用 Alt+ F4 快捷键或关闭手势来关闭应用。 |

7.4 使用 SessionState 存储状态

问题

您需要存储应用在整个生命周期中的状态,以便可以在应用激活时恢复其价值。

解决办法

使用WinJS.Application.sessionState将数据存储到应用的状态,可用于在应用暂停或终止后恢复应用。

它是如何工作的

WinJS.Application.sessionState对象用于存储应用信息,以便在应用暂停或终止后恢复应用的状态。

当应用暂停然后重新启动时,它不会丢失其状态。但是当应用被挂起,然后操作系统由于内存或其他原因终止应用时,应用的状态就会丢失。再次启动时,该应用将从头开始。

WinJS.Application.sessionState有助于克服这个问题。

让我们用一些代码来演示 SessionState 的用法。

Create a new Universal Windows project using the Universal Windows template, which can be found under the JavaScript ➤ Windows ➤ Universal node of the New Project dialog in Microsoft Visual Studio 2015. This creates a single project in the Visual Studio Solution along with the necessary files in it to start.   Open the default.html page from Visual Studio Solution Explorer and replace it with the following code snippet. <!DOCTYPE html> <html> <head>     <meta charset="utf-8" />     <title>Recipe7.4</title>     <!-- WinJS references -->     <link href="WinJS/css/ui-light.css" rel="stylesheet" />     <script src="WinJS/js/base.js"></script>     <script src="WinJS/js/ui.js"></script>     <!-- Recipe7.4 references -->     <link href="/css/default.css" rel="stylesheet" />     <script src="/js/default.js"></script> </head> <body class="win-type-body" style="margin: 20px"> <div>     <input id="txt1"/>     <input id="txt2"/> </div> </body> </html> The preceding code snippet adds two input controls on the page so that the user can enter data.   Open the default.js file from the js folder and replace the onactivated and oncheckpoint events with the following code snippet. app.onactivated = function (args) {                 if (args.detail.kind === activation.ActivationKind.launch) {                     if (args.detail.previousExecutionState === Windows.ApplicationModel.Activation.ApplicationExecutionState.notRunning) {                         console.log("setting the initial values");                         document.getElementById("txt1").value = '';                         document.getElementById("txt2").value = '';                     }                     if (args.detail.previousExecutionState === Windows.ApplicationModel.Activation.ApplicationExecutionState.closedByUser) {                         console.log("setting the initial values");                         document.getElementById("txt1").value = '';                         document.getElementById("txt2").value = '';                     }                     if (args.detail.previousExecutionState === Windows.ApplicationModel.Activation.ApplicationExecutionState.terminated) {                         console.log("setting the previous state values");                         document.getElementById("txt1").value = WinJS.Application.sessionState.txt1;                         document.getElementById("txt2").value = WinJS.Application.sessionState.txt2;                     }                         args.setPromise(WinJS.UI.processAll());                 }         };         app.oncheckpoint = function (args) {             WinJS.Application.sessionState.txt1 = document.getElementById("txt1").value;             WinJS.Application.sessionState.txt2 = document.getElementById("txt2").value;         };

代码片段处理onactivatedoncheckpoint事件。当应用暂停时,触发oncheckpoint事件。在此阶段,用户在两个文本框中输入的值保存在sessionState中。

如果应用的先前状态被终止,当应用被重新激活时,sessionState的值被恢复并更新到页面上的文本框中。如果先前的状态不是 Running 或 closedByUser,则恢复默认值。

当你运行已经挂起和终止的应用时,你会在页面中看到恢复的应用数据,如图 7-5 所示。

A978-1-4842-0719-2_7_Fig5_HTML.jpg

图 7-5。

Page displaying the data restored from the sessionState

您可以从 Visual Studio 2015 测试应用状态并模拟挂起和终止的事件。为此,您需要使用调试位置工具栏中的生命周期事件下拉列表,如图 7-6 所示。

A978-1-4842-0719-2_7_Fig6_HTML.jpg

图 7-6。

Tool to test the Application Lifecycle events from Visual Studio

可以通过单击暂停选项在应用运行时暂停应用,然后单击恢复选项恢复应用来模拟暂停和恢复生命周期事件。单击暂停选项时,会引发onCheckpoint事件。通过单击暂停和关闭按钮,可以模拟暂停和终止事件。此时,onCheckpoint事件被引发,您的应用终止。当您再次运行应用时,previousExecutionState包含终止值。

7.5 使用超链接在页面间导航

问题

你需要以一种最简单的方式在通用 Windows 应用的页面间导航。

解决办法

使用 HTML 在应用页面间导航的最简单方法之一是使用超链接。

它是如何工作的

假设你的 app 中有default.htmlnewpage.html文件,如果你想从default.html导航到newpage.html,在default.html中添加以下代码就可以做到这一点。

<p><a href="newpage.html">Navigate to page 2</a></p>

代码中的href是引用newpage.html的相对链接。这是一个 HTML 页面,是您的通用 Windows 应用的一部分,应该位于项目的根目录中。

或者,如果您希望指定作为应用一部分的本地文件的 URI,您可以使用名为 ms-appx 的新包内容 URI 方案。

前面的代码可以重写如下:

<p><a href="ms-appx:///newpage.html">Navigate to New page</a></p>

Note

尽管这个菜谱执行顶层导航,但您必须避免在 Windows 应用中这样做。这是网页的理想选择,但不适合手机或平板电脑应用。有时候,当应用加载下一页时,屏幕可能会变成空白。

微软建议使用单页导航,与顶级导航相比,它提供了更好的性能和更像应用的体验。

7.6 使用单页导航在页面之间导航

问题

您需要使用单页导航模式在通用 Windows 应用的页面之间导航。

解决办法

在通用 Windows 应用中实现单页导航的最简单的解决方案之一是使用必要的文件来执行从 Windows 8.1 导航应用模板到 Windows 10 项目的导航逻辑。

Note

在撰写本文时,Windows 10 没有提供类似于 Windows 8.1 中的导航模板。

它是如何工作的

Visual Studio 2015 没有为 UWP 应用提供导航模板。它只提供空白的应用模板。幸运的是,VS 2015 还包括 Windows 8.1 应用的模板和一个做大量导航逻辑的模板。让我们将 Windows 8.1 项目中的必要文件包含到通用 Windows 应用中。

启动 Visual Studio 2015,使用导航 App 模板新建一个 Windows 8.1 项目,如图 7-7 所示。

A978-1-4842-0719-2_7_Fig7_HTML.jpg

图 7-7。

Creating Windows 8.1 project using Navigation App

这个模板添加了navigator.js文件,并用导航逻辑更新了default.js。这些文件可以在项目的js文件夹下找到。

该模板还创建了一个名为pages的文件夹,并包含一个包含三个文件的home子文件夹:home.csshome.htmlhome.js

pages文件夹包含所有页面控件,就像 Windows 应用中的页面。启动导航应用模板时,默认加载pagecontrol home.html文件。这是在default.html页面中设置的。

加载页面控件的所有细节都由PageControlNavigator处理,它是navigator.js文件的一部分。

下一步是创建一个新的通用 Windows 应用,并对其进行更新,以包含使用 Windows 8.1 导航模板创建的项目中的文件。

A978-1-4842-0719-2_7_Fig8_HTML.jpg

图 7-8。

Including the js folder and pages folder to UWP App in Visual Studio 2015 Create a new Universal Windows Project using the Universal Windows template, which can be found under the JavaScript ➤ Windows ➤ Universal node of the New Project dialog in Microsoft Visual Studio 2015. This creates a single project in the Visual Studio Solution along with the necessary files in it to start.   Copy the complete js folder and the pages folder from the Windows 8.1 Navigation App that was created earlier and paste it into the root of the new Universal Project. Include them in the project from Visual Studio Solution Explorer, as shown in the Figure 7-8.

现在,您已经准备好修改通用 Windows 应用来执行页面之间的导航。

从 Visual Studio 解决方案资源管理器中打开default.html页面,并用以下代码替换 body 部分。

<div id="contenthost" data-win-control="Application.PageControlNavigator" data-win-options="{home: '/pages/home/home.html'}"></div>

另外,在default.html页面中包含对navigator.js的引用。

<script src="/js/navigator.js"></script>

default.html页面就像一个外壳,用于从pages文件夹中加载不同的页面控件。默认情况下,它从pages / home文件夹中加载home.html页面。

PageControlNavigator 控件具有一个 id,其内容主机值充当从页面控件加载的内容的主机。

下一步是向项目添加一个新的页面控件,这样用户就可以从home.html文件导航到新的页面控件。

Microsoft Visual Studio 提供了页面控件项模板,允许开发人员轻松创建页面控件。

在 Visual Studio 解决方案资源管理器中右击pages文件夹,并从上下文菜单中选择“添加➤新项”。在“添加新项”对话框中,选择“页面控制”并提供名称“page2.html”。单击添加按钮。

这会将三个文件添加到项目中:

  • page1.html
  • page1.css
  • page1.js

接下来显示了page1.html的内容。

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8" />

<title>page1</title>

<link href="page1.css" rel="stylesheet" />

<script src="page1.js"></script>

</head>

<body>

<div class="page1 fragment">

<header class="page-header" aria-label="Header content" role="banner">

<button class="back-button" data-win-control="WinJS.UI.BackButton"></button>

<h1 class="titlearea win-type-ellipsis">

<span class="pagetitle">Welcome to page1</span>

</h1>

</header>

<section class="page-section" aria-label="Main content" role="main">

<p>The content of page 2</p>

</section>

</div>

</body>

</html>

page1.js文件的内容如下:

// For an introduction to the Page Control template, see the following documentation:

//http://go.microsoft.com/fwlink/?LinkId=232511

(function () {

"use strict";

WinJS.UI.Pages.define("/pages/page1.html", {

// This function is called whenever a user navigates to this page. It

// populates the page elements with the app's data.

ready: function (element, options) {

},

unload: function () {

},

updateLayout: function (element) {

}

});

})();

您将只修改page1.html的 body 标签,以表明导航到第 1 页是成功的。

现在,通用应用中有两个 HTML 页面。第一页是home.html,第二页是page1.html。如何在两个页面之间导航?

您可以使用WinJS.Navigate.navigate()方法在页面之间导航。

让我们通过添加下面的代码片段来修改home.html以包含一个导航到第 1 页的超链接。

<a id="lnkPage2"> Navigate to Page 2</a>

注意,超链接有id属性,但没有href属性。

打开home.js文件,用下面的代码片段替换它。

(function () {

"use strict";

WinJS.UI.Pages.define("/pages/home/home.html", {

// This function is called whenever a user navigates to this page. It

// populates the page elements with the app's data.

ready: function (element, options) {

var page2link = document.getElementById('lnkPage2');

page2link.addEventListener('click', function(eventargs) {

eventargs.preventDefault();

WinJS.Navigation.navigate("/pages/page1.html");

});

}

});

})();

该代码为页面的 ready 事件中的超链接设置 click 事件处理程序。click 事件处理程序首先调用preventDefault函数阻止正常的链接导航,然后调用WinJS.Navigation.navigate方法导航到page1.html

当您使用本地机器选项在 Windows 桌面上运行应用时,您会看到显示有超链接的主页,如图 7-9 所示。

A978-1-4842-0719-2_7_Fig9_HTML.jpg

图 7-9。

home.html page with a hyperlink to navigate to page 2

当点击导航到第 2 页链接时,用户被带到第 2 页,如图 7-10 所示。当您查看page2.html时,请注意后退按钮,它会将您带回上一页。

A978-1-4842-0719-2_7_Fig10_HTML.jpg

图 7-10。

Page1.html with the Back button

表 7-4 显示了WinJS.Navigation类中可用的一些方法。

表 7-4。

WinJS.Navigation Class

| 方法名称 | 描述 | | --- | --- | | WinJS。Navigation.back() | 此方法将用户导航回历史记录中的上一页。 | | WinJS。Navigation.forward() | 这种方法使开发人员能够在历史中向前导航。 | | WinJS。Navigation.navigate() | 该方法使开发人员能够导航到指定的页面。 |

八、全球化和本地化

有机会在近 240 个 Windows 市场中推广您的 Windows 应用。目标受众在文化、地区和语言方面各不相同。您的应用的用户可能位于世界上的任何地方。他们可能说不同的语言,甚至是多种语言。作为应用开发人员,您有必要使您的应用适应多种语言、市场、文化和地区。全球化意味着让您的应用了解文化、语言和地区。本地化是将您的应用的某些方面本地化到它正在运行的文化的能力;例如,日期、数字或货币格式等等。在这一章中,你将看到如何全球化和本地化你的应用的方法。

8.1 使用资源字符串

问题

当你的 app 在非英语文化中使用,文本不适应新的文化和语言;相反,用户看到的是英文文本。

解决办法

为了全球化应用,有必要使用资源字符串来代替静态文本。例如,应用中的任何标签文本都不应该硬编码为静态文本。相反,应该为您需要支持的文化/语言创建资源文件。添加将文本翻译成相应语言的字符串。标签文本也使用资源字符串,而不是硬编码。

它是如何工作的

让我们看看资源字符串在应用中的用法,以及如何添加它们。

Open Visual Studio 2015. Select File ➤ New Project ➤ JavaScript ➤ Windows ➤ Universal and select Blank App (Universal Windows) template. This will create a universal app with the necessary files that can run on machines powered by Windows 10.

A978-1-4842-0719-2_8_Fig1_HTML.jpg

图 8-1。

Choosing the Blank App (Universal Windows) template in the New Project window   Open the package.appxmanifest file from the project in Visual Studio solution explorer. Go to the Application tab and check that the default language is set to en-US. When a new project is created, the language is set to en-US by default (see Figure 8-2).

A978-1-4842-0719-2_8_Fig2_HTML.jpg

图 8-2。

Default language settings in the application manifest   Create a resource folder, as follows:

A978-1-4842-0719-2_8_Fig3_HTML.jpg

图 8-3。

Strings folder in the Windows project In the Solution Explorer, select the Universal Windows project and right-click on it. Select Add ➤ New Folder from the context menu.   Name the new folder strings. You will create different culture/language resource files inside this folder (see Figure 8-3).     Create a subfolder and an English resource file, as follows: Create a folder named en-US in the strings folder (created in step 3).   Right-click the en-US folder and select Add ➤ New Item.   Select Text File from the template and give the name resources.resjson for the file. It is recommended to use this default name when naming the resource file.   Replace the content of the file with the following content: { "greeting"          : "Hello World!", "_greeting.comment" : "Hello World Text comment", "farewell"          : "Goodbye", "_farewell.comment" : "A farewell comment." }   The resource file is nothing but a JSON file with key value pairs. Here, "greeting" and "farewell" identify the strings that will be displayed. The other keys— "_greeting.comment" and "_farewell.comment" are comments that describe the strings itself. It’s a good practice to have meaningful comments for all of your strings.   Use string resource identifiers to do the following: Open the default.js file in the project from the Visual Studio solution explorer. This file can be found in the js folder of the project.   Add the following line of code to the app.onactivated function: WinJS.Resources.processAll(); The completed code should look as follows: app.onactivated = function (args) {         if (args.detail.kind === activation.ActivationKind.launch) {             if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {                 WinJS.Resources.processAll();             } else {             }             args.setPromise(WinJS.UI.processAll());         }     };   To use the resource string in your markup, open the default.html file and add the following content in the body: <h2> <span data-win-res="{textContent: 'greeting'}"></span></h2> <h2> <span data-win-res="{textContent: 'farewell'}"></span> </h2>     Add additional language resource files: In the strings folder of the project, add a folder named de-DE. This is for German culture.   Add a resource file in the de-DE folder. Name the resource file resources.resjson. Replace the content of the file with the following code: {         "greeting"          : "Hallo Welt!",         "_greeting.comment" : " Hello World Text comment.",         "farewell"          : "Auf Wiedersehen",         "_farewell.comment" : "A farewell comment." }   Add another folder in the strings folder of the project and name it fr-FR. This is for French culture.   Add a resource file in the fr-FR folder. This resource file name should also be resources.resjson. Replace the content of the file with the following code: {         "greeting"          : "Salut tout le monde",         "_greeting.comment" : "Hello World Text comment.",         "farewell"          : "Au revoir",         "_farewell.comment" : "A farewell comment." }     Run the app, as follows: Build and run the app by pressing F5.   Greeting and farewell messages are displayed in a user’s preferred language, set on the device. Figure 8-4 shows the output on a Windows screen run using the Local Machine option.

A978-1-4842-0719-2_8_Fig4_HTML.jpg

图 8-4。

English culture resource strings display   Change the language setting on the device and run the app again. Figure 8-5 shows the same text displayed with the language set to French on the device.

A978-1-4842-0719-2_8_Fig5_HTML.jpg

图 8-5。

French culture resource strings display.

请注意,在 Windows Mobile 上更改语言设置时,您必须重新启动设备。

8.2 格式化日期、时间、数字和货币

问题

当语言更改为非英语区域性/语言时,日期、时间、数字和货币显示英语区域性设置。

解决办法

应用中的静态文本内容可以通过使用资源字符串进行本地化。但是如果您的应用必须显示日期、时间、数字或货币,您就不能使用资源字符串。相反,您需要使用WinJS.Globalization名称空间,它提供了日期时间、数字和货币格式助手方法的功能。

它是如何工作的

格式化日期和时间

以下步骤解释了如何设置日期和时间的格式。

Use DateTimeFormatter in the Windows.Globalization.DateTimeFormatting namespace. Create a DateTimeFormatter instance with a template format. For a list of template formats, you can check the MSDN documentation at http://msdn.microsoft.com/en-us/library/windows/apps/windows.globalization.datetimeformatting.datetimeformatter.aspx .   Add the following markup to default.html file inside the body element: <h1>Formatting Demo</h1> <br /> <h3>Long Date:</h3> <h3 id="spnDate"></h3> <br /> <h3>Long Time:</h3> <h3 id="spnTime"></h3>   Modify the onactivated method in default.js as follows: app.onactivated = function (args) {         if (args.detail.kind === activation.ActivationKind.launch) {             if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {                 var lang = Windows.System.UserProfile.GlobalizationPreferences.languages[0];                 var shortDateFmt = new Windows.Globalization.DateTimeFormatting.DateTimeFormatter("longdate", [lang]);                 var shortTimeFmt = new Windows.Globalization.DateTimeFormatting.DateTimeFormatter("longtime",[lang]);                 var currentDateTime = new Date();                 var shortDate = shortDateFmt.format(currentDateTime);                 var shortTime = shortTimeFmt.format(currentDateTime);                 document.getElementById("spnDate").innerHTML = shortDate;                 document.getElementById("spnTime").innerHTML = shortTime;             } else {                 // TODO: This application has been reactivated from suspension.                 // Restore application state here.             }             args.setPromise(WinJS.UI.processAll());         } };   Run the app and verify the output (see Figure 8-6 and Figure 8-7).

A978-1-4842-0719-2_8_Fig7_HTML.jpg

图 8-7。

Formatted output for French culture

A978-1-4842-0719-2_8_Fig6_HTML.jpg

图 8-6。

Formatted output for English culture

图 8-6 显示英语文化格式的日期,图 8-7 显示法语文化格式的日期。

格式化数字和货币

以下步骤解释了如何设置数字和货币的格式:

NumberFormatting should be used to display decimal and percentage numbers and currencies.   Add the following markup in default.html and append to the body: <h3>Number Format:</h3> <h3 id="spnCurrency"></h3>   Modify the onactivated method in default.js and append the following code:    var userCurrency = Windows.System.UserProfile                         .GlobalizationPreferences.currencies; var number = 23456.78 var currFmt = new Windows.Globalization.NumberFormatting                         .CurrencyFormatter(userCurrency[0],[lang]); var formattedCurrency = currFmt.format(number); document.getElementById("spnCurrency").innerHTML =                 formattedCurrency;   Run the app by pressing F5. Change the language settings on your phone or tablet to see the number and currency formatting in action (see Figure 8-8 and Figure 8-9).

A978-1-4842-0719-2_8_Fig9_HTML.jpg

图 8-9。

Date and currency formatted output in French culture

A978-1-4842-0719-2_8_Fig8_HTML.jpg

图 8-8。

Date and currency formatted output in English culture

8.3 本地化 WinJS 控件

问题

当区域性或语言更改时,WinJS 控件不显示本地化字符串。

解决办法

通常,像labeltitle这样的控件属性被设置在标记中。这有点像对字符串值进行硬编码。因此,当区域性或语言更改时,控件不会适应,并按原样显示硬编码的字符串。通过使用资源文件,可以将 WinJS 控件属性绑定到本地化字符串。WinJS 提供了直接将控件属性绑定到资源文件中的资源键的灵活性。

它是如何工作的

下列步骤解释如何本地化 WinJS 控件:

Open Visual Studio 2015. Select File ➤ New Project ➤ JavaScript ➤ Windows ➤ Blank App (Universal Windows). This will create a universal app which is a single project that can run on devices powered by Windows 10.   Add resource files to the project (see Recipe 8.1 on how to add resource files).   Add the following string keys: { "ShowMoreTilesTitle"            : "Show more Tiles", "_ShowMoreTilesTitle.comment"   : "show more tiles toggle title", "VibrateOnCallTitle"            : "Vibrate on Call", "_VibrateOnCallTitle.comment"   : "vibrate on call toggle title", "ShowArtistTitle"            : "Show artist when playing music", "_ShowArtistTitle.comment"   : "Show artist when playing music                         toggle title", "ToggleOn"              : "Yes", "_ToggleOn.comment"     : "show more tiles toggle on label", "ToggleOff"             : "No", "_ToggleOff.comment"    : "show more tiles toggle off label" } Similarly, I have also added strings for other languages.   Add the following code to the default.js onactivated method: WinJS.UI.processAll().then(function(){      WinJS.Resources.processAll(); }); You need to call processAll() on the WinJS.Resource class because you will be referring to the resource strings in the markup.   Add the following markup to default.html inside the body element: <div> <h1>Controls Localization</h1> <br /> <div class="toggle" data-win-control="WinJS.UI.ToggleSwitch"      data-win-res="{winControl: {labelOn:'ToggleOn',                                  labelOff:'ToggleOff',                                  title:'ShowMoreTilesTitle'}}"      data-win-options=""> </div> <br /> <div class="toggle" data-win-control="WinJS.UI.ToggleSwitch"      data-win-res="{winControl: {labelOn:'ToggleOn',                                  labelOff:'ToggleOff',                                  title:'VibrateOnCallTitle'}}"      data-win-options=""> </div> <br /> <div class="toggle" data-win-control="WinJS.UI.ToggleSwitch"      data-win-res="{winControl: {labelOn:'ToggleOn',                                  labelOff:'ToggleOff',                                  title:'ShowArtistTitle'}}"      data-win-options=""> </div> </div> Notice that you use data-win-res and refer the resource strings by their key names, and assign it to a property of the control. Usually, it is of the following pattern: data-win-res="{winControl: {propertyName1:'resourceID1',                                 propertyName2:'resourceID2'}}"   Press F5 and run the app. Initially, you will see an English string used by the control. Change the Language in the device and then run the app again. Now it will pick up the appropriate resource file and use the appropriate resource strings (see Figure 8-9 and Figure 8-10).

A978-1-4842-0719-2_8_Fig11_HTML.jpg

图 8-11。

Formatted output in English culture

A978-1-4842-0719-2_8_Fig10_HTML.jpg

图 8-10。

Formatted output in French culture

九、数据存储和应用数据

本章概述了在 Windows 10 应用中存储应用数据的数据存储技术。您将了解应用设置、如何将应用设置存储和检索为应用数据,以及如何使用应用数据文件夹。

那么什么是 app 数据呢?特定于特定应用的数据称为应用数据。通常,应用数据是用户的偏好、应用的配置、应用的状态等等,这些都是可变的。

当您在设备上安装应用时,应用会在设备上创建应用数据。但是,当你从设备上移除或卸载应用时,会发生什么呢?卸载应用时,应用数据会从设备中移除。所以建议不要将用户的数据(比如用户的图片)存储为 app 数据。

应用创建的另一种数据是用户数据。用户数据由用户创建,例如文档、图片、视频文件、音频文件等等。

9.1 如何创建和删除本地应用数据设置容器

问题

您需要在 Windows 10 应用的应用数据存储中创建和删除本地应用数据存储容器。

解决办法

使用Windows.Storage.ApplicationData.current.LocalSettings.createContainer在本地应用数据存储中创建本地应用设置容器。

它是如何工作的

该容器允许您组织您的应用数据设置;例如,您可以创建一个名为Greeting_Data_Container的容器来存储应用的所有问候语。创建另一个名为UserPreference_Container的容器,为您的应用用户存储所有用户偏好设置。您可以在本地设置和漫游设置中添加容器。一个容器中还可以有另一个容器。通用 Windows 应用允许您创建多达 32 个嵌套级别的容器。

Create a new project using the Windows Universal (Blank App) template in Microsoft Visual Studio 2015. This creates a Windows Universal app, which can be run on PCs, tablets, and Windows Phones running Windows 10.   Open the default.html page from the project in Visual Studio Solution Explorer.   Define an HTML tag for a button within the <body> tag of default.html. <div id="titleBarContent" style="width: 100%;height:30px; background:border-box darkblue; overflow: hidden; z-index: 3">         <i>App Settings Admin Screen</i>     </div> <span> Click on the button to Create a local app data settings container</span>     <input type="button" value="Local Data Demo" id="btnLocalData" />    <h3><span id="msgspan"></span></h3> The complete default.html code will look like this: <!DOCTYPE html> <html> <head>     <meta charset="utf-8" />     <title>Recipe9.1</title>     <!-- WinJS references -->     <link href="WinJS/css/ui-dark.css" rel="stylesheet" />     <script src="WinJS/js/base.js"></script>     <script src="WinJS/js/ui.js"></script>     <!-- Recipe9.1 references -->     <link href="/css/default.css" rel="stylesheet" />     <script src="/js/default.js"></script> </head> <body class="win-type-body">     <div id="titleBarContent" style="width: 100%;height:30px; background:border-box darkblue; overflow: hidden; z-index: 3">         <i>App Settings Admin Screen</i>     </div>         <span> Click on the button to Create a local app data settings container</span>     <input type="button" value="Local Data Demo" id="btnCreateContainer" />    <h3><span id="msgspan"></span></h3> </body> </html>   Right-click the project’s js folder in Solution Explorer and add a js file in the project’s js folder by using the Add ➤ New JavaScript file. Provide a name for the file. In this example, let’s name the file DatastorageDemo.js.   Refer to this file in default.html by adding the following code to the <head> tag: <script src="js/DatastorageDemo.js"></script>   Add the following code to the newly created js file: (function () {     "use strict";     function GetControl() {         WinJS.UI.processAll().done(function () {   var localSettingsButton = document.getElementById("btnCreateContainer"); localSettingsButton.addEventListener("click", btnCreateContainerClick, false);         });     }     document.addEventListener("DOMContentLoaded", GetControl); })();

这段代码获取按钮元素,并将一个事件侦听器绑定到按钮,当用户单击按钮时,该事件侦听器被触发。现在,使用下面的代码片段在DatastorageDemo.js文件中添加一个事件方法或函数。

function btnCreateContainerClick(mouseEvent) {

var applicationData = Windows.Storage.ApplicationData.current;

var localSettings = applicationData.localSettings;

// Creating a local settings container

var localSettingscontainer = localSettings.createContainer("App_GreetingDataContainer", Windows.Storage.ApplicationDataCreateDisposition.Always);

document.getElementById("msgspan").innerText = "Container Created, the name of the container is :" + localSettingscontainer.name;

}

这段代码声明了一个名为applicationData的变量。它被分配了Windows.Storage.ApplicationData.current,允许您访问 app 数据存储。应用数据存储可以存储应用设置和文件。下一行代码从变量ApplicationData中检索localSettings到变量localSettings

然后它调用createContainer方法来创建一个设置容器。前面的示例创建了一个设置容器App_greetingDatacreateContainer方法有两个参数:设置容器的名称和Windows.Storage.ApplicationDataCreateDisposition.Always,表示总是检查容器是否存在。如果存在,返回指定的容器;否则,创建一个新的。

您也可以使用localSettingscontainer.deleteContainer("<<name>>")方法删除容器。deleteContainer方法从应用数据存储中删除容器。

删除代码片段使用hasKey函数检查容器是否存在,然后使用deleteContainer函数通过传递容器键删除容器。

这里给出了DataStorageDemo.js的完整代码:

(function () {

"use strict";

function GetControl() {

WinJS.UI.processAll().done(function () {

var localSettingsButton = document.getElementById("btnCreateContainer");

localSettingsButton.addEventListener("click", btnCreateContainerClick, false);

});

}

document.addEventListener("DOMContentLoaded", GetControl);

})();

function btnCreateContainerClick(mouseEvent) {

var applicationData = Windows.Storage.ApplicationData.current;

var localSettings = applicationData.localSettings;

// Creating a local settings container

var localSettingscontainer = localSettings.createContainer("App_GreetingDataContainer", Windows.Storage.ApplicationDataCreateDisposition.Always);

document.getElementById("msgspan").innerText = "Container Created, the name of the container is :" + localSettingscontainer.name;

}

现在,让我们构建应用,并在 Windows 10 中运行它。

图 9-1 展示了一个按钮和一个h2标签的外观。当您单击本地数据演示按钮时,它执行btnSaveClick方法,该方法创建容器并显示一条带有容器名称的消息。

A978-1-4842-0719-2_9_Fig1_HTML.jpg

图 9-1。

Creating a local app data settings container

9.2 如何创建和读取本地应用数据设置

问题

您需要在应用数据存储中的应用数据设置容器中创建本地应用数据设置。

解决办法

使用ApplicationDataContainer.values在 Windows 10 应用的本地应用数据存储中的应用数据设置容器中创建本地应用数据设置。

它是如何工作的

应用设置是应用中的个性化数据或自定义设置。用户偏好——例如用户想要启用还是停用定位服务——是一个应用设置。通用 Windows 应用开发公开了 API,允许您在应用数据存储中将应用设置作为应用数据进行存储和检索。

app store 由两个不同的设置位置组成:本地设置和漫游设置。

Create a new project using the Windows Universal (Blank App) template in Microsoft Visual Studio 2015.   Open the default.html page from the project in Visual Studio Solution Explorer.   Define HTML tags for two text boxes, a button, and a <span> tag within the <body> tag of default.html. <div id="titleBarContent" style="width: 100%;height:30px; background:border-box darkblue; overflow: hidden; z-index: 3">   <i>App Settings Admin Screen (Use this Screen to configure app Settings)</i>  </div>     <br />     <i>Welcome Greeting in English</i> <input type="text" value="" id="txtWelcomeGreetingseng" /><br />     <i>Welcome Greeting in French</i><input type="text" value="" id="txtWelcomeGreetingsfr" /><br />   <input type="button" value="Create Local App Data Demo" id="btnLocalData" /> The complete default.html contains should look like this: <!DOCTYPE html> <html> <head>     <meta charset="utf-8" />     <title>Recipe9.2</title>     <!-- WinJS references -->     <link href="WinJS/css/ui-dark.css" rel="stylesheet" />     <script src="WinJS/js/base.js"></script>     <script src="WinJS/js/ui.js"></script>     <!-- Recipe9.2 references -->     <link href="/css/default.css" rel="stylesheet" />     <script src="/js/default.js"></script> </head> <body class="win-type-body">     <div id="titleBarContent" style="width: 100%;height:30px; background:border-box darkblue; overflow: hidden; z-index: 3">         <i>App Settings Admin Screen (Use this Screen to configure app Settings)</i>     </div>     <br />     <i>Welcome Greeting in English</i> <input type="text" value="" id="txtWelcomeGreetingseng" /><br />     <i>Welcome Greeting in French</i><input type="text" value="" id="txtWelcomeGreetingsfr" /><br />     <input type="button" value="Create Local App Data Demo" id="btnLocalData" /> </body> </html>   Right-click the project’s js folder in Solution Explorer and select Add ➤ New JavaScript file. Provide a name for the file. In this example, let’s name the file DataStorageDemo.js. (function () {     "use strict";     function GetControl() {         WinJS.UI.processAll().done(function () {             var submitbutton = document.getElementById("btnLocalData");             submitbutton.addEventListener("click", btnLocalDataClick, false);         }); GetCurrentSettingValues();     }     document.addEventListener("DOMContentLoaded", GetControl); })();   Now, add a function to retrieve the current greeting settings from the container: function GetCurrentSettingValues() {     var applicationData = Windows.Storage.ApplicationData.current;     var localSettings = applicationData.localSettings;     // Creating a local settings container     var containerExists = localSettings.containers.hasKey("App_GreetingDatalocalContainer");     if (containerExists) {         document.getElementById("txtWelcomeGreetingseng").value = localSettings.containers.lookup("App_GreetingDatalocalContainer").values["App_Heading_English"];         document.getElementById("txtWelcomeGreetingsfr").value = localSettings.containers.lookup("App_GreetingDatalocalContainer").values["App_Heading_French"];     } }

此代码在应用加载时执行;它从容器中检索本地问候语设置。首次运行此应用时,您不会看到任何填充的值,但下次运行时,它会显示存储在容器中的设置。

现在,使用下面的代码片段在DataStorageDemo.js文件中添加一个事件方法或函数:

function btnLocalDataClick(mouseEvent) {

var applicationData = Windows.Storage.ApplicationData.current;

var localSettings = applicationData.localSettings;

// Creating a local settings container

var localSettingscontainer = localSettings.createContainer("App_GreetingDatalocalContainer", Windows.Storage.ApplicationDataCreateDisposition.Always);

if (!localSettingscontainer.values.hasKey("App_Heading_English")) {

localSettingscontainer.values["App_Heading_English"] = document.getElementById("txtWelcomeGreetingseng").value;

}

if (!localSettingscontainer.values.hasKey("App_Heading_French")) {

localSettingscontainer.values["App_Heading_French"] = document.getElementById("txtWelcomeGreetingsfr").value;

}

} //end of function btnLocalDataClick

这段代码创建了applicationDatalocalSettings变量来引用localSettings。之后,它使用createContainer函数创建一个名为App_GreetingDatalocalContainer的容器。然后,它使用localSettingscontainer.values.hasKey("App_Heading_English")来确保名为App_Heading_English的设置存在于应用数据的 localSettings 容器中。如果设置不存在,那么它使用localSettingscontainer.["name"]函数创建一个。它还通过使用以下代码行将文本框中的字符串值赋给它:

localSettingscontainer.values["App_Heading_English"] = document.getElementById("txtWelcomeGreetingseng").value;

对于法语标题的应用也是如此。

当您在 Windows 10 上运行该应用时,您会看到如图 9-2 所示的屏幕。

A978-1-4842-0719-2_9_Fig2_HTML.jpg

图 9-2。

Creating local app data settings for the greetings settings

9.3 如何创建和检索本地复合设置

问题

您需要在 Windows 10 应用的应用数据存储中创建和读取本地复合值。

解决办法

使用ApplicationDataCompositeValue类来创建和读取本地复合值。

它是如何工作的

Windows.Storage.ApplicationDataCompositeValue类允许您创建可存储在本地设置或漫游设置中的复合设置。复合值类允许您将名称值对作为应用数据存储在应用数据存储中。假设您想将图书信息存储为

book["ISBN"] = 12345;

book["BookTitle"] = "Windows 10 Development";

要存储复合信息,您可以使用如下所示的代码:

var applicationData = Windows.Storage.ApplicationData.current;

var localSettings = applicationData.localSettings;

// Create a BookInfo Composite setting

var bookInfo = new Windows.Storage.ApplicationDataCompositeValue();

bookInfo["ISBN"] = 12345;

bookInfo["Title"] = "Windows 10 Development";

localSettings.values["AppLocalSettings"] = bookInfo;

要从复合设置中读取数据,可以使用如下所示的代码:

var bookInfo = localSettings.values["AppLocalSettings"];

if (bookInfo)

{

var ISBN = bookInfo["ISBN"];

var Title = bookInfo["Title"]

}

9.4 如何创建漫游应用数据存储容器

问题

您需要在 Windows 10 应用的应用数据存储中创建一个漫游应用数据存储容器。

解决办法

使用roamingSettings.createContainer在应用数据存储中创建漫游应用设置容器。

它是如何工作的

这和你在 app data store 的本地设置中看到的非常相似,但是你没有使用Windows.Storage.ApplicationData.current.LocalSettings,而是使用了Windows.Storage.ApplicationData.current.roamingSettings

Create a new project using the Windows Universal (Blank App) template in Microsoft Visual Studio 2015.   Open the default.html page from the project in Visual Studio Solution Explorer. Add the following HTML markup within the body tag of default.html: <body class="win-type-body" style="background-color:goldenrod"> <div id="titleBarContent" style="width: 100%;height:30px; background:border-box darkblue; overflow: hidden; z-index: 3">         <i>User Preferences Settings Screen (These settings will be available across devices)</i>     </div>    <br />     <input type="button" value="Save User Preference" id="btnUserPreferenceRoamingData" />     <br />     <span id="spantoDisplayRoamingData" style="color:white"></span> </body>   Right-click the project’s js folder in the Solution Explorer and select Add ➤ New JavaScript file. Provide the name for the file. In this example, let’s name the file DatastorageDemo.js. (function () {     "use strict";     function GetControl() {         WinJS.UI.processAll().done(function () {             var submitbutton = document.getElementById("btnUserPreferenceRoamingData");             submitbutton.addEventListener("click", btnCreateRoamingContainerClick, false);         });     }     document.addEventListener("DOMContentLoaded", GetControl); })();   Now, add an event method or function using the following code snippet in the Datastoragedemo.js file: function btnCreateRoamingContainerClick(mouseEvent) { var ApplicationData = Windows.Storage.ApplicationData.current; var roamingSettings = ApplicationData.roamingSettings; // Creating a local settings container if (!roamingSettings.containers.hasKey("UserPreference_RoamingProfile")) { var roamingSettingscontainer = roamingSettings.createContainer("UserPreference_RoamingProfile", Windows.Storage.ApplicationDataCreateDisposition.Always); document.getElementById("spantoDisplayRoamingData").innerText =roamingSettingscontainer.name +" User Preference Roaming App Data Container Created!!";    } }

这段代码声明了一个名为ApplicationData的变量。它被分配了Windows.Storage.ApplicationData.current,这表示应用数据存储中应用设置的容器。下一行从ApplicationData中检索roamingSettings,并将其存储在roamingSettings变量中。

然后它调用roamingSettings.containers.hasKey函数来检查容器是否存在。如果它不存在,那么它使用createContainer方法创建一个设置容器。前面的示例创建了一个设置容器App_GreetingDataRoamingContainer,并将其存储在roamingSettingscontainer中。createContainer方法有两个参数:设置容器的名称和Windows.Storage.ApplicationDataCreateDisposition.Always,它指示总是检查容器是否存在;如果存在,返回指定的容器;否则,创建一个新的。

当您在 Windows 10 模拟器或 Windows Mobile 上运行该应用时,它应该如图 9-3 所示。

A978-1-4842-0719-2_9_Fig3_HTML.jpg

图 9-3。

The form to save user preference settings using roaming app data settings

太好了。在前面的代码片段中,您学习了roamingSettings对象的createContainerdeleteContainer方法。

9.5 如何创建和读取漫游应用数据设置

问题

您需要在 Windows 10 应用的应用数据存储中的漫游应用数据设置容器中创建和读取漫游应用数据设置。

解决办法

使用ApplicationDataContainer.values在 Windows 10 应用的应用数据商店的应用数据设置容器中创建漫游应用数据设置。

它是如何工作的

Create a new project using the Windows Universal (Blank App) template in Microsoft Visual Studio 2015.   Open the default.html page from the project in Visual Studio Solution Explorer.   Add a form control to the body section of the page. The form control has a few div controls to display the title bar, input control for email, and a toggle switch control for mobile data and location services. <body class="win-type-body">     <div id="titleBarContent" style="width: 100%;height:30px; background:border-box darkblue; overflow: hidden; z-index: 3">         <i>User Preferences Settings Screen (These settings will be available across devices)</i>     </div>     <br />     <form id="form1">         <fieldset class="formSection">             <legend class="formSectionHeading">User Preferenses</legend>             <div class="twoColumnFormContainer">                 <div id="UserMobileData" data-win-control="WinJS.UI.ToggleSwitch" data-win-options="{title :'Use Mobile Data',labelOff: 'Disabled',belOn:'Enabled',hecked: true}">                 </div>                 <br />                 <div id="LocationServices" data-win-control="WinJS.UI.ToggleSwitch" data-win-options="{title :'Location Services',labelOff: 'Disabled',belOn:'Enabled',hecked: true}">                 </div>                 <br />                 <div id="msg" style="color:red"></div>                 <br />                 <div class="buttons">                         <button type="submit" id="btnSubmit" class="horizontalButtonLayout win-button">                             Submit                         </button>                 </div>             </div>         </fieldset>     </form>     <br /> </body>   Right-click the project in Solution Explorer and select Add ➤ New JavaScript file and provide the name for the file. In this example, let’s name the file DataStorageDemo.js.   Add the following code to the DataStorageDemo.js file: (function () {     "use strict";     function GetControl() {         WinJS.UI.processAll().done(function () {             var submitbutton = document.getElementById("btnSubmit");             submitbutton.addEventListener("click", btnCreateRoamingContainerClick, false);         });     }     document.addEventListener("DOMContentLoaded", GetControl); })();

前面的代码向btnSubmit按钮添加了一个事件接收器。现在添加一个btnCreateRoamingContainerClick函数,当用户单击用户首选项表单控件上的提交按钮时触发该函数。

function btnCreateRoamingContainerClick(mouseEvent) {

var ApplicationData = Windows.Storage.ApplicationData.current;

var roamingSettings = ApplicationData.roamingSettings;

// Creating a local settings container

if (roamingSettings.containers.hasKey("UserPreference_RoamingProfile")) {

var roamingSettingscontainer = roamingSettings.createContainer("UserPreference_RoamingProfile", Windows.Storage.ApplicationDataCreateDisposition.Always);

var toggleMobileDataButton = document.getElementById("UserMobileData").winControl;

if (toggleMobileDataButton.checked) {

roamingSettingscontainer.values["UseMobileData"] = "Yes";

}

else {

roamingSettingscontainer.values["UseMobileData"] = "No";

}

var toggleLocationDataButton = document.getElementById("LocationServices").winControl;

if (toggleLocationDataButton.checked) {

roamingSettingscontainer.values["LocationServices"] = "Yes";

}

else {

roamingSettingscontainer.values["LocationServices"] = "No";

}

document.getElementById("msg").innerText = "Data Saved!!";

}

}//end of function btnCreateRoamingContainerClick

这段代码声明了一个名为ApplicationData的变量。它被分配了Windows.Storage.ApplicationData.current,表示应用数据存储中应用设置的容器。下一行从ApplicationData中获取roamingSettings,并将其存储在roamingSettings变量中。

然后它调用roamingSettings.containers.hasKey函数来检查容器是否存在。如果它不存在,它使用createContainer方法创建一个设置容器。前面的示例创建了一个设置容器App_GreetingDataRoamingContainer,并将其存储在roamingSettingscontainer中。createContainer方法有两个参数:设置容器的名称和Windows.Storage.ApplicationDataCreateDisposition.Always,它指示总是检查容器是否存在。如果存在,返回指定的容器;否则,创建一个新的。

下一行代码检查切换开关控件的值,基于它是否被选中。如果切换开关选择“是”,它将使用roamingSettingscontainer.values["UseMobileData"]功能存储漫游数据应用设置,该功能使用container.value方法设置值。它也为位置服务拨动开关做同样的事情。

DataStorageDemo.js文件中的完整代码如下所示:

(function () {

"use strict";

function GetControl() {

WinJS.UI.processAll().done(function () {

var submitbutton = document.getElementById("btnSubmit");

submitbutton.addEventListener("click", btnCreateRoamingContainerClick, false);

});

}

document.addEventListener("DOMContentLoaded", GetControl);

function btnCreateRoamingContainerClick(mouseEvent) {

var ApplicationData = Windows.Storage.ApplicationData.current;

var roamingSettings = ApplicationData.roamingSettings;

// Creating a local settings container

if (roamingSettings.containers.hasKey("UserPreference_RoamingProfile")) {

var roamingSettingscontainer = roamingSettings.createContainer("UserPreference_RoamingProfile", Windows.Storage.ApplicationDataCreateDisposition.Always);

var toggleMobileDataButton = document.getElementById("UserMobileData").winControl;

if (toggleMobileDataButton.checked) {

roamingSettingscontainer.values["UseMobileData"] = "Yes";

}

else {

roamingSettingscontainer.values["UseMobileData"] = "No";

}

var toggleLocationDataButton = document.getElementById("LocationServices").winControl;

if (toggleLocationDataButton.checked) {

roamingSettingscontainer.values["LocationServices"] = "Yes";

}

else {

roamingSettingscontainer.values["LocationServices"] = "No";

}

document.getElementById("msg").innerText = "Data Saved!!";

}

}//end of function btnCreateRoamingContainerClick

})();

就这样。漫游数据将在用户访问此 Win 10 应用的所有设备上可用。

当您在 Windows 10 模拟器或 Windows Mobile 上运行该应用时,它将如图 9-4 所示。

A978-1-4842-0719-2_9_Fig4_HTML.jpg

图 9-4。

Form to save user preference settings using roaming app data settings

9.6 如何注册数据变更事件

问题

您需要注册并实现一个数据更改事件处理程序。

解决办法

您可以使用ApplicationData.DataChanged事件注册漫游数据的数据更改事件。

它是如何工作的

当漫游数据在其中一个设备上更改时,通用 Windows 应用会将漫游数据复制到云,然后将漫游数据同步到用户安装了应用的其他设备。假设在同步之后,您希望确保基于漫游数据更新应用数据。例如,您将用户首选项存储在漫游数据中,当用户首选项更改时,您希望根据新的首选项更改用户设备上的设置。嗯,通用 Windows 应用允许您注册一个事件,该事件将在应用数据刚刚完成从云同步后执行。

您可以使用ApplicationData.DataChanged事件来注册一个事件。所以我们来实现这个。

Create a new project using the Windows Universal (Blank App) template in Microsoft Visual Studio 2015. This creates a Windows Universal app that can run on Windows tablets and Windows Phone running Windows 10.   Open the default.html page from the project in Visual Studio Solution Explorer.   Define an HTML div tag for the app title bar.

<body class="win-type-body">

<div id="titleBarContent" style="width: 100%;height:30px; background:border-box darkblue; overflow: hidden; z-index: 3">

<i>Custom title bar</i>

</div>

</body>

完整的default.html代码将如下所示:

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8" />

<title>_9.7</title>

<!-- WinJS references -->

<link href="WinJS/css/ui-dark.css" rel="stylesheet" />

<script src="WinJS/js/base.js"></script>

<script src="WinJS/js/ui.js"></script>

<!-- _9.7 references -->

<link href="/css/default.css" rel="stylesheet" />

<script src="/js/default.js"></script>

<script src="/js/DatastorageDemo.js"></script>

</head>

<body class="win-type-body">

<div id="titleBarContent" style="width: 100%;height:30px; background:border-box darkblue; overflow: hidden; z-index: 3">

<i>Custom title bar</i>

</div>

</body>

</html>

在解决方案资源管理器中右键单击该项目,然后选择“添加➤新 JavaScript 文件”。提供文件的名称。在本例中,我们将文件命名为 DatastorageDemo.js。

js文件中添加以下代码。代码首先向applicationData对象注册一个数据更改事件。

(function () {

"use strict";

function GetControl() {

WinJS.UI.processAll().done(function () {

});

}

document.addEventListener("DOMContentLoaded", GetControl);

var applicationData = Windows.Storage.ApplicationData.current;

applicationData.addEventListener("datachanged", datachangeHandler);

function datachangeHandler(eventArgs) {

var applicationData = Windows.Storage.ApplicationData.current;

var roamingSettings = applicationData.roamingSettings;

// Creating a roaming settings container

var roamingSettingscontainer = roamingSettings.containers ("App_GreetingDataContainer");

//Read the Data again

document.getElementById("titleBarContent").innerText = roamingSettingscontainer.values["App_Heading_English"];

}

})();

这段代码还在同一个js文件中定义了 data changed 事件处理程序。datachangeHandler事件通过使用loopup函数从applicationData对象中检索漫游容器。然后它读取名为App_Heading_English的漫游设置,并将其分配给标题栏的div选项卡。

9.7 如何创建、写入和读取本地文件

问题

您需要在 Windows 10 应用的应用数据存储中创建文件、写入文件和读取文件。

解决办法

使用Windows.Storage.StorageFile类进行文件处理。

它是如何工作的

Windows.Storage.StorageFile类为通用 Windows 应用中的文件处理提供了必要的方法。您创建的文件可以存储在文件夹、库(图片库)和通用 Windows 应用支持的网络位置中,如 OneDrive 等。

本地文件夹

众所周知,通用的 Windows 应用可以在许多设备上运行:Windows Mobile、运行 Windows 10 的个人电脑、微软 Surface 平板电脑等等。因此,当您在 Windows 应用商店中部署应用时,您的应用用户可以在一台或多台设备上下载并运行您的应用。那么如何在特定设备上管理特定于你的应用的应用设置呢?你可以使用本地文件夹。本地文件夹可用于在特定设备上存储本地应用数据。本地文件夹数据可用于存储该数据的设备。它不能与其他设备同步。通用 Windows 应用将应用数据存储在应用包的LocalState中。

漫游文件夹

现在,假设您想要存储应用的用户首选项,并且想要确保相同的用户首选项在特定用户的所有设备上都可用。嗯,你可以通过使用漫游文件夹来实现这一点。它将应用数据存储在应用包的RoamingState中。当应用用户在多个设备上运行应用时,存储在漫游文件夹中的应用数据会在设备之间同步。

临时文件夹

第三种类型的位置是临时文件夹,它允许您短期存储应用数据。储存在临时文件夹中的应用数据一旦不再使用,就会被删除。所以总是使用这个文件夹来存储不太重要的数据。通用 Windows 应用将应用数据存储在应用包的TemporaryState中。

StorageFolder类公开了许多创建文件、从文件中读取内容以及将内容写入文件的方法。让我们来看看每一种方法。

方法在指定的位置创建一个新文件。如果文件已经存在,它将覆盖该文件。

使用该函数的语法如下:

storageFolder.createFileAsync(desiredName).done(function CreationSuccess(newFileObj))

{

/* Success call back */

}, CreationFailed(error))

{

Failed call back */

});

如您所见,createFileAsync方法必须使用一个成功的回调函数和一个失败的回调函数来定义。

在本地文件夹中创建文件的完整代码如下:

function btnDataToFileClick(mouseEvent) {

var ApplicationData = Windows.Storage.ApplicationData.current;

var localFolder = ApplicationData.localFolder;

var newFilePromise = localFolder.createFileAsync("MyFile.txt");

newFilePromise.done(

function (file) {

// WinJS.log("The file MyFile.txt was created.", "sample", "status");

WinJS.log && WinJS.log("The file MyFile.txt was created.", "sample", "status");

},

function (error) {

});

}

当你在你的 Windows 10 本地设备上运行这个应用时,会在本地文件夹中创建一个名为MyFile.txt的文件,如图 9-5 所示。

A978-1-4842-0719-2_9_Fig5_HTML.jpg

图 9-5。

A file created in local folder

本地文件夹位置为C:\Users\<<UserName>>\AppData\Local\Packages\5342d954-ee4c-413c-8ed8-41b3befa6afc_khbmmdtkmdajr\LocalState。这个文件是空的,因为我们还没有写入这个文件。

太好了。现在让我们编写代码将内容写入文件。为此,我们首先在default.html文件中添加一个文本区域框。default.html的 body 标签看起来像这样:

<body class="win-type-body" style="background-color:goldenrod">

<div id="titleBarContent" style="width: 100%;height:30px; background:border-box darkblue; overflow: hidden; z-index: 3">

<i>File Handling Demo</i>

</div>

<br />

<input type="button" value="Save Data to File" id="btnCreateAFile" />

<textarea rows="10" cols="100" id="textarea" class="win-textarea"></textarea>

<input type="button" value="Save Data to File" id="btnDataToFile" />

</body>

这段代码向default.html文件添加了一个文本区域,以及名为btnDataToFilebtnCreateaFile的按钮。

在解决方案资源管理器中右键单击项目的 js 文件,然后选择“添加➤新 JavaScript 文件”。提供文件的名称。在本例中,我们将文件命名为 DatastorageDemo。js。

(function () {

"use strict";

function GetControl() {

WinJS.UI.processAll().done(function () {

var submitbutton = document.getElementById("btnCreateAFile");

submitbutton.addEventListener("click", btnCreateAFileClick, false);

var submitbutton = document.getElementById("btnDataToFile");

submitbutton.addEventListener("click", btnDataToFileClick, false);

});

}

document.addEventListener("DOMContentLoaded", GetControl);

})();

这段代码将事件接收器添加到两个按钮控件中。现在在 DatastorageDemo.js 文件中添加一个事件代码。

function btnCreateAFileClick(mouseEvent) {

var ApplicationData = Windows.Storage.ApplicationData.current;

var LocalFolder = ApplicationData.localFolder;

var newFilePromise = LocalFolder.createFileAsync("MyFile.txt");

newFilePromise.done(

function (file) {

// WinJS.log("The file MyFile.txt was created.", "sample", "status");

WinJS.log && WinJS.log("The file MyFile.txt was created.", "sample", "status");

},

function (error) {

});

}

这段代码用于在本地文件夹中创建一个新文件。您不会为btnDataToFile的点击事件向DataStorageDemo.js文件添加另一个事件。

function btnDataToFileClick(mouseEvent) {

var ApplicationData = Windows.Storage.ApplicationData.current;

var LocalFolder = ApplicationData.localFolder;

// Open sample file.

var FilePromise = LocalFolder.getFileAsync("MyFile.txt");

FilePromise.then(function (file) {

// If file found …

if (file) {

// Write to file.

var txtarea = document.getElementById("textarea").innerText;

Windows.Storage.FileIO.writeTextAsync(file, txtarea).then(function (contents) {

WinJS.log && WinJS.log("The text was wrttien to file MyFile.txt.", "sample", "status");

});

}

}, function (error) {

// Handle error.

});

}

这段代码通过使用本地文件夹的getFileAsync方法获取文件。如果文件存在,那么它接下来使用Windows.Storage.FileIO.writeTextAsync.writeTextAsync方法将内容写入文件。

当您在 Visual Studio 中使用本地设备运行此应用时,您会看到默认屏幕,如图 9-6 所示。

A978-1-4842-0719-2_9_Fig6_HTML.jpg

图 9-6。

File handling demo’s default screen

“创建文件”按钮会在运行应用的设备的本地文件夹中创建一个文件。创建文件后,在文本区域键入一些文本。单击将数据保存到文件将数据保存到文件。当您在记事本中打开该文件时,您会看到该文件的内容,如图 9-7 所示。

A978-1-4842-0719-2_9_Fig7_HTML.jpg

图 9-7。

The file on the local holder with the content

类似地,您可以使用readTextAsync方法来读取文件的内容。从文件中读取内容的代码如下:

// Read from the file.

Windows.Storage.FileIO.readTextAsync(file).then(function (contents) {

document.getElementById("textarea1").innerText = contents;

});

您可以通过引用正确的位置,以类似的方式在任何位置创建文件,如本地文件夹、漫游文件夹等。

十、共享数据

本章介绍如何在通用 Windows 平台应用之间共享数据。共享数据使开发人员能够构建允许用户共享信息、复制/粘贴以及从一个应用拖放到另一个应用的功能。例如,用户可能想要从一个应用中复制一些文本或图像,并将其粘贴到另一个应用中。用户也寻找共享信息/社交网站的链接。

Windows 10 应用支持以两种不同的方式共享数据。

  • 源应用允许用户将应用中的数据共享给其他应用。
  • 目标应用允许用户将一个应用声明为目标应用,该应用可以从其他应用检索共享数据。声明为目标应用的应用允许用户在共享数据时选择它作为目标应用。

通过使用共享数据选项,用户可以与其他应用共享纯文本、网络链接、照片和视频。在本章中,您将学习如何实现从源应用共享数据和声明目标应用。

共享联系人

为了共享数据或接收数据,每个应用都需要作为源应用或目标应用实现共享契约。数据共享包括以下三个部分:

  • 源 app:源 app 实现共享契约作为源 app 共享数据。此应用注册数据传输管理器,并填充要共享的数据包。
  • Share broker:Share broker 是 Share charm,支持源应用和目标应用之间的通信。
  • 目标应用:目标应用作为目标应用实现共享契约,以接收其他应用共享的数据。

10.1 为源应用的共享选项设置事件处理程序

问题

您需要为源应用的共享选项设置事件处理程序。

解决办法

你需要使用Windows.ApplicationModel.DataTransfer.DataTransferManagerdatarequested事件监听器。

它是如何工作的

当用户调用共享时,Windows.ApplicationModel.DataTransfer.DataTransferManager类的datarequested事件监听器方法被触发。此事件可以由用户操作触发,也可以在特定情况下自动触发;例如,当用户完成一项调查,应用想要分享调查结果。

要用DataTransferManager对象注册事件处理程序,可以使用下面的代码:

var dataTransferManager = Windows.ApplicationModel.DataTransfer.DataTransferManager.getForCurrentView();

dataTransferManager.addEventListener("datarequested", dataRequested_Share);

在前面的代码中,您做的第一件事是使用DataTransferManager.getForCurrentView()函数获取当前页面的DataTransferManager对象。

接下来的一行代码将为datarequested事件添加一个事件监听器到DataTransferManager对象中。在前面的代码中,dataRequested_Share是监听器,datarequested是事件。然后,您可以定义接收方,如下面的代码所示。

function dataRequested_Share () {

// Your code for the sharing data

}

让我们使用前面的代码创建一个通用的 Windows 应用,为源应用的共享选项设置事件处理程序。

在 Microsoft Visual Studio 2015 中使用 Windows 通用(空白应用)模板创建一个新项目。

在解决方案资源管理器中右键单击项目的js文件夹,并选择添加➤新 JavaScript 文件。提供文件的名称。在本例中,我们将文件命名为 DataSharingDemo。js。

(function () {

"use strict";

function GetControl() {

WinJS.UI.processAll().done(function () {

var dataTransferManager = Windows.ApplicationModel.DataTransfer.DataTransferManager.getForCurrentView();

dataTransferManager.addEventListener("datarequested", shareDataHandler);

});

}

document.addEventListener("DOMContentLoaded", GetControl);

})();

function shareDataHandler(e) {

// Your code to share the text, image etc

}

前面的代码使用DataTransferManager.getForCurrentView()函数获取当前页面的DataTransferManager对象,然后向其添加一个事件侦听器,如前所述。

现在,将DataSharingDemo.js引用添加到default.html,如下所示:

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8" />

<title>_10.1</title>

<!-- WinJS references -->

<link href="WinJS/css/ui-dark.css" rel="stylesheet" />

<script src="WinJS/js/base.js"></script>

<script src="WinJS/js/ui.js"></script>

<!-- _10.1 references -->

<link href="/css/default.css" rel="stylesheet" />

<script src="/js/default.js"></script>

<script src="/js/DataSharingDemo.js"></script>

</head>

<body class="win-type-body">

<p>Content goes here</p>

</body>

</html>

10.2 将纯文本数据共享给其他应用

问题

你需要开发一个功能,允许用户将纯文本数据分享给其他 Windows 10 应用。

解决办法

使用request.data.setTextrequest.Data.Properties.description共享数据。request.data.title 是必填字段。

它是如何工作的

在前面的菜谱中,您了解到当用户使用 Share charm 开始共享会话时,会触发datarequested事件监听器。所以现在我们将在监听器中编写代码来共享数据。侦听器接受一个参数,该参数是事件参数。首先,您需要从事件参数中检索请求对象,如下所示:

function shareDataHandler(e) {

//Start your code to share data

var request = e.request;

}

您需要为请求对象设置属性。为了共享纯文本,您需要填充以下属性:

request.Data.Properties.Title = "Title of the Data";

request.Data.Properties.Description = "Description of the Data";

太好了,看起来很简单,不是吗?让我们实现它,看看在应用之间共享数据的现场演示。

在 Microsoft Visual Studio 2015 中使用 Windows 通用(空白应用)模板创建一个新项目。

首先,将下面的代码添加到default.html中。您需要用以下代码替换 body 标记:

<body class="win-type-body" style="background-color:white">

<div>

<p style="color:black">Enter Project Title:</p>

<input class="text-box" id="txttitle" value="Project Title" size="40"/>

<p style="color:black">Enter Project Description:</p>

<input class="text-box" id="txtdesc" value="Project Desc" size="40" />

<p style="color:black">Enter Project Weekly Summary:</p>

<textarea id="txttext" maxlength="1000" style="width:50%">Weekly Status: Here is the weekly status</textarea>

<br />

<br />

</div>

</body>

这段代码为共享数据演示定义了一个用户界面。用户界面如图 10-1 所示。

A978-1-4842-0719-2_10_Fig1_HTML.jpg

图 10-1。

Sharing Data user interface

现在,在解决方案浏览器中右键单击项目的js文件夹,并选择添加➤新 JavaScript 文件。提供文件的名称。在本例中,我们将文件命名为 DataSharingDemo.js。

(function () {

"use strict";

function GetControl() {

WinJS.UI.processAll().done(function () {

var dataTransferManager = Windows.ApplicationModel.DataTransfer.DataTransferManager.getForCurrentView();

dataTransferManager.addEventListener("datarequested", shareDataHandler);

});

}

document.addEventListener("DOMContentLoaded", GetControl);

})();

还将以下代码添加到default.html中,以引用DataSharingDemo.js文件:

<script src="/js/DataSharingDemo.js"></script>

这样,您就有了想要共享的数据的用户界面。您还为datarequested事件添加了事件监听器。现在,共享数据特性最重要的部分是实现填充请求对象的代码。因此,将函数shareDataHandler的以下代码添加到DataSharingDemo.js文件中。

function shareDataHandler(e) {

var request = e.request;

// The request.data.properties.title is mandatory

var ShareInfoTitle = document.getElementById("txttitle").value;

if (ShareInfoTitle !== "") {

var ShareInfoDesc = document.getElementById("txtdesc").value;

if (ShareInfoDesc !== "") {

request.data.properties.title = ShareInfoTitle;

request.data.properties.description = ShareInfoDesc;

var ShareInfoFullText = document.getElementById("txttext").value;

if (ShareInfoFullText !== "") {

request.data.setText(ShareInfoFullText);

}

} else {

request.failWithDisplayText("Please Enter the Project Details you would like to share.");

}

} else {

request.failWithDisplayText("Error Occured!!");

}

}

前面的代码首先从事件参数中检索请求对象。该函数填充如下:

request.data.properties.title = ShareInfoTitle;

request.data.properties.description = ShareInfoDesc;

最后,添加以下代码:

request.data.setText(ShareInfoFullText);

这个函数检查标题是否为空,因为请求的 title 属性是必需的。

当您在 Windows 10 上运行该应用时,您会看到如图 10-2 所示的屏幕。

A978-1-4842-0719-2_10_Fig2_HTML.jpg

图 10-2。

Sharing Data demo

现在点击共享图标或按下 Windows 徽标键A978-1-4842-0719-2_10_Figa_HTML.jpg + H。您将看到如图 10-3 所示的屏幕。

A978-1-4842-0719-2_10_Fig3_HTML.jpg

图 10-3。

The Share charm windows showing the project title as a sharing data object

现在,从列表中单击 OneNote。你会看到一个屏幕,如图 10-4 所示。

A978-1-4842-0719-2_10_Fig4_HTML.jpg

图 10-4。

OneNote showing the shared data from the Universal Windows app

10.3 共享其他应用的网络链接

问题

你需要开发一个功能,允许用户与其他 Windows 10 应用共享网页链接。

解决办法

使用request.data.setWebLink以及标题和描述字段。

它是如何工作的

要共享 web 链接,需要使用request对象的request.data.setWebLink()方法。

在 Microsoft Visual Studio 2015 中使用 Windows 通用(空白应用)模板创建一个新项目。

首先,将下面的代码添加到default.html中。您需要用以下代码替换 body 标记:

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8" />

<title>_10.3</title>

<!-- WinJS references -->

<link href="WinJS/css/ui-dark.css" rel="stylesheet" />

<script src="WinJS/js/base.js"></script>

<script src="WinJS/js/ui.js"></script>

<!-- _10.3 references -->

<link href="/css/default.css" rel="stylesheet" />

<script src="/js/default.js"></script>

<script src="/js/DataSharingDemo.js"></script>

</head>

<body class="win-type-body" style="background-color:white">

<div>

<p style="color:black">Enter Project Title:</p>

<input class="text-box" id="txttitle" value="Project Title" size="40" />

<p style="color:black">Enter Project Description:</p>

<input class="text-box" id="txtdesc" value="Project Desc" size="40" />

<p>Enter Project Site URL</p>

<input class="text-box" id="txtURL" value="Enter Project Site URL" size="40" />

<br />

<br />

</div>

</body>

</html>

现在,在解决方案资源管理器中右键单击项目的js文件夹,并选择添加➤新 JavaScript 文件。提供文件的名称。在本例中,我们将文件命名为 DataSharingDemo。js。

(function () {

"use strict";

function GetControl() {

WinJS.UI.processAll().done(function () {

var dataTransferManager = Windows.ApplicationModel.DataTransfer.DataTransferManager.getForCurrentView();

dataTransferManager.addEventListener("datarequested", shareDataHandler);

});

}

document.addEventListener("DOMContentLoaded", GetControl);

})();

还将以下代码添加到default.html中,以引用DataSharingDemo.js文件:

<script src="/js/DataSharingDemo.js"></script>

DataSharingDemo.js增加一个新的shareDataHandler函数。完整的shareDataHandler函数如下所示。下面使用request.data.setWebLink()功能来设置正在共享的网页链接。

function shareDataHandler(e) {

var request = e.request;

// The request.data.properties.title is mandate

var ShareInfoTitle = document.getElementById("txttitle").value;

if (ShareInfoTitle !== "") {

var ShareInfoDesc = document.getElementById("txtdesc").value;

if (ShareInfoDesc !== "") {

request.data.properties.title = ShareInfoTitle;

request.data.properties.description = ShareInfoDesc;

var ShareURL = document.getElementById("txtURL").value;

if (ShareURL !== "") {

request.data.setWebLink(new Windows.Foundation.Uri(ShareURL));

}

} else {

request.failWithDisplayText("Please Enter the Project Details you would like to share.");

}

} else {

request.failWithDisplayText("Error Occured!!");

}

}

request.data.setWebLink()方法接受一个 URI 类型的参数,这就是为什么在把它传递给函数之前,从字符串到Windows.Foundation.Uri的转换是必要的。

10.4 将图片分享给其他应用

问题

你需要开发一个功能,允许用户与其他 Windows 10 应用共享图像。

解决办法

使用request.data.setStorageItemsrequest.data.setBitmap以及标题和描述字段。您也可以使用这两种方式来共享图像,因为您不知道目标应用支持哪种方式。

它是如何工作的

通用 Windows 应用还允许您与其他应用共享图像。您可以允许用户从本地设备选择图像,然后使用“共享”功能与其他应用共享。让我们看看图片分享的实际应用。

首先,将下面的代码添加到default.html中。您需要用以下代码替换 body 标记:

<body class="win-type-body" style="background-color:white">

<div>

<p style="color:black">Enter Project Title:</p>

<input class="text-box" id="txttitle" value="Project Title" size="40" />

<p style="color:black">Enter Project Description:</p>

<input class="text-box" id="txtdesc" value="Project Desc" size="40" />

<p>Select the image to share</p>

<button class="action" id="selectImageButton">Select image</button>

<br />

<br />

</div>

<div class="imageDiv">

<img class="imageHolder" id="imageHolder" alt="image holder" src="" />

</div>

</body>

前面的代码定义了一个带有图像拾取器按钮的共享图像的用户界面。

现在在DataSharingDemo.js文件中添加以下函数。

(function () {

"use strict";

var objimgFile;

function GetControl() {

WinJS.UI.processAll().done(function () {

var objimgFile = null;

var dataTransferManager = Windows.ApplicationModel.DataTransfer.DataTransferManager.getForCurrentView();

dataTransferManager.addEventListener("datarequested", shareDataHandler);

document.getElementById("selectImageButton").addEventListener("click", selectImage, false);

});

}

document.addEventListener("DOMContentLoaded", GetControl);

})();

前面的代码向selectImageButton控件添加了一个监听器,如粗体行所示。

除了添加一个侦听器之外,它还声明了一个名为objimgFile的变量,该变量保存您将在下面的函数中使用的图像对象。

添加一个selectImage函数,它是 Select Image 按钮的 click 事件的监听器。该功能使用FileOpenPicker方法,允许用户从设备中选择图像。

function selectImage() {

var picker = new Windows.Storage.Pickers.FileOpenPicker();

picker.fileTypeFilter.replaceAll([".jpg", ".bmp", ".gif", ".png"]);

picker.viewMode = Windows.Storage.Pickers.PickerViewMode.thumbnail;

picker.pickSingleFileAsync().done(function (file) {

if (file) {

// Display the image to the user

document.getElementById("imageHolder").src = URL.createObjectURL(file, { oneTimeOnly: true });

// The imageFile variable will be set to shareValue when the user clicks Set

objimgFile = file;

}

});

}

一旦选取器成功选择了单个文件,它就调用async方法,然后设置src属性。

现在,让我们将shareDataHandler()方法添加到js文件中,如下所示:

function shareDataHandler(e) {

var request = e.request;

// The request.data.properties.title is mandate

var ShareInfoTitle = document.getElementById("txttitle").value;

if (ShareInfoTitle !== "") {

var ShareInfoDesc = document.getElementById("txtdesc").value;

if (ShareInfoDesc !== "") {

request.data.properties.title = ShareInfoTitle;

request.data.properties.description = ShareInfoDesc;

if (objimgFile != null) {

//Create a stream variable and using randomStreamReference.createFromFile //function create the stream for the image file object "objimgFile"

var imageStream = Windows.Storage.Streams.RandomAccessStreamReference.createFromFile(objimgFile);

request.data.setStorageItems([objimgFile]);

// The setBitmap method requires a stream object

request.data.setBitmap(imageStream);

}

} else {

request.failWithDisplayText("Please Enter the Project Details you would like to share.");

}

} else {

request.failWithDisplayText("Error Occured!!");

}

}

shareDataHandler函数首先设置request.data对象的标题和描述。为了设置图像,它使用 stream 对象,如下面的代码所示:

var imageStream = Windows.Storage.Streams.RandomAccessStreamReference.createFromFile(objimgFile);

这一行创建一个流变量,并使用createFromFile函数为图像文件objimgFile对象创建流。

下一行通过传递 image 对象来调用request.data对象的setStorageItems函数。objimgfile对象被设置为selectImage()文件夹中的一个文件。

request.data.setStorageItems([objimgFile]);

前面代码中的下一行是request.data对象的setBitMap方法,它将图像设置为共享的数据对象:

// pass the stream imageStream to the setBitMap method

request.data.setBitmap(imageStream);

当您在 Windows 10 上使用 Share charm 功能运行应用时,您会看到选择图像按钮,如图 10-5 所示。

A978-1-4842-0719-2_10_Fig5_HTML.jpg

图 10-5。

Sharing image demo

点按“选择图像”按钮,并从设备相机文件夹或照片文件夹中选择图像。一旦你选择了照片,你就会在你的default.html文件中看到该图像,如图 10-6 所示。

A978-1-4842-0719-2_10_Fig6_HTML.jpg

图 10-6。

Sharing Image demo

现在单击共享图标或按下 Windows 徽标键A978-1-4842-0719-2_10_Figb_HTML.jpg + H。当您从列表中选择 OneNote 时,应用将与 OneNote 共享数据,您将看到如图 10-7 所示的屏幕。

A978-1-4842-0719-2_10_Fig7_HTML.jpg

图 10-7。

Image shared along with project title

10.5 将应用声明为共享目标

问题

当用户使用 Share charm 功能时,您需要在列表中声明一个应用作为共享目标。

解决办法

package.appxmanifest文件中配置共享目标,使共享契约成为共享目标 app。

它是如何工作的

当用户使用 Share charm 调用共享时,Windows 10 会显示一个可能的目标应用列表。目标共享应用是可以接收其他应用共享的数据的应用。您需要将您的应用声明为目标应用,并实现接收数据并将其存储在正确的位置或显示在屏幕上的功能。例如,您有两个应用:一个用于时间管理报告,另一个用于组织中的项目列表。如果你想把时间管理报告的数据分享给项目列表应用,该怎么办?时间管理报告应用将成为源应用,项目列表应用将成为目标应用。

当您将一个应用声明为可以接收其他应用共享的数据的目标应用时,您的应用遵守共享契约。通过将您的应用声明为目标应用,您可以为您的应用用户提供良好的体验,从而增强与其他应用的社交连接。

如果您希望通过共享选项从其他应用接收数据或支持共享契约,则需要将您的应用声明为共享目标。

要将您的应用声明为共享目标,请遵循以下准则:

Open the manifest file (package.appxmanifest), which is available in the root folder of the project.   Click the Declaration tab.   From the available declarations, select Share Target.   On the right side of the screen, enter Sharing Description.   Select the data format by clicking Add new.   Define two data formats: Text and Image.

申报设置窗口应如图 10-8 所示。

A978-1-4842-0719-2_10_Fig8_HTML.jpg

图 10-8。

Image shared along with project title

当你在 Windows 10 中运行应用并使用 Share charm 功能时,你会看到你的应用出现在列表中,如图 10-9 所示。

A978-1-4842-0719-2_10_Fig9_HTML.jpg

图 10-9。

Share Charm windows

让我们回顾一下共享契约支持的数据类型。表 10-1 列出了使用共享契约的共享数据中支持的数据类型。

表 10-1。

Data Types in Share Contract

| 数据类型 | 描述 | | --- | --- | | 文本 | 纯文本字符串 | | 上呼吸道感染 | 一个网页链接(例如, [`http://www.apress.com`](http://www.apress.com) ) | | 图像 | 位图图像 | | 超文本标记语言 | HTML 内容 | | 文件 | 作为存储项目的文件 | | 自定义数据 | 使用 JSON 格式的自定义数据 | | 多信息文本 | 富文本格式的字符串 |

10.6 处理共享激活并接收纯文本

问题

您需要将共享激活作为共享目标应用来处理。

解决办法

当您的应用出现在 Share charm 的目标应用列表中时,用户可以从列表中选择您的应用来共享数据。当用户选择您的应用来共享数据时,会触发Application.OnShareTargetActivated事件。

它是如何工作的

当您的应用被选择用于共享数据时,会触发一个 Application.OnShareTargetActivated 事件。您的应用需要实现此事件来接收用户从其他应用共享的数据。

让我们在一个通用的 Windows 应用中实现这个事件,以便从其他应用接收数据。

在 Microsoft Visual Studio 2015 中使用 Windows 通用(空白应用)模板创建一个新项目。

首先,将下面的代码添加到default.html中。您需要用以下代码替换 body 标记:

<body class="win-type-body">

<div>

<br /><br />

<div>The following Data  was received from the source app:</div>

<br />

<h3>Data Properties</h3>

<strong>Title: </strong><span id="txttitle" data-win-automationId="Title">(No title)</span><br />

<strong>Description: </strong><span id="txtdescription" data-win-automationId="Description">(No description)</span><br />

<strong>Data: </strong><span id="txtdata" data-win-automationId="Description">(No data)</span><br />

</div>

</body>

这段代码为共享数据演示定义了一个用户界面。用户界面如图 10-10 所示。

A978-1-4842-0719-2_10_Fig10_HTML.jpg

图 10-10。

Share Charm windows

现在,右键单击解决方案资源管理器中的项目,并选择添加➤新 JavaScript 文件。提供文件的名称。在本例中,我们将文件命名为 DataSharingDemo。js。

(function () {

"use strict";

function GetControl() {

WinJS.UI.processAll().done(function () {

// Initialize the activation handler

WinJS.Application.addEventListener("activated", activatedShareHandler, false);

});

}

document.addEventListener("DOMContentLoaded", GetControl);

})();

上述代码将一个激活的事件侦听器添加到 application 对象中。名为activatedShareHandler的事件监听器函数提供如下:将该函数添加到js文件中。

/// <summary>

/// Function to handle the activation

/// </summary>

/// <param name="eventArgs">

/// Arguments of the event. In the case of the Share contract, it has the ShareOperation

/// </param>

function activatedShareHandler(eventObject) {

// Check if the Share Contract was the cuase of this sharing

if (eventObject.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.shareTarget) {

eventObject.setPromise(WinJS.UI.processAll());

// ShareOperation object in initiliaze with the eventObject event arugment

shareOperation = eventObject.detail.shareOperation;

//check if shareOperation has text Sharing enable or data shared using text

if (shareOperation.data.contains(Windows.ApplicationModel.DataTransfer.StandardDataFormats.text)) {

shareOperation.data.getTextAsync().done(function (text) {

dispReceivedContent(text);

}, function (e) {

displayError("Text: ", "Error retrieving data: " + e);

});

}

}

}

前面的代码接收activatedShareHandler事件监听器的共享数据。这段代码首先检查共享是否是由共享契约触发的。然后,它从事件参数创建一个shareOperation对象,如以下代码所示:

// ShareOperation object in initiliaze with the eventObject event arugment

shareOperation = eventObject.detail.shareOperation;

然后,代码使用shareOperation.data.getTextAsync函数异步获取文本。在异步调用的 success 方法中,接收到的文本然后被传递给dispReceivedContent()函数,该函数然后在目标应用上显示文本。以下是显示共享内容功能的代码:

function dispReceivedContent(content) {

document.getElementById("txttitle").innerText = shareOperation.data.properties.title;

document.getElementById("txtdescription").innerText = shareOperation.data.properties.description;

document.getElementById("txtdata").innerText = content;

}

这里显示了DataSharingDemo.js文件的完整代码:

(function () {

"use strict";

function GetControl() {

WinJS.UI.processAll().done(function () {

// Initialize the activation handler

WinJS.Application.addEventListener("activated", activatedShareHandler, false);

});

}

document.addEventListener("DOMContentLoaded", GetControl);

})();

/// <summary>

/// Function to handle the activation

/// </summary>

/// <param name="eventArgs">

/// Arguments of the event. In the case of the Share contract, it has the ShareOperation

/// </param>

function activatedShareHandler(eventObject) {

// Check if the Share Contract was the cause of this sharing

if (eventObject.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.shareTarget) {

eventObject.setPromise(WinJS.UI.processAll());

// ShareOperation object in initiliaze with the eventObject event argument

shareOperation = eventObject.detail.shareOperation;

//check if shareOperation has text Sharing enable or data shared using text

if (shareOperation.data.contains(Windows.ApplicationModel.DataTransfer.StandardDataFormats.text)) {

shareOperation.data.getTextAsync().done(function (text) {

dispReceivedContent(text);

}, function (e) {

displayError("Text: ", "Error retrieving data: " + e);

});

}

}

}

function dispReceivedContent(content) {

document.getElementById("txttitle").innerText = shareOperation.data.properties.title;

document.getElementById("txtdescription").innerText = shareOperation.data.properties.description;

document.getElementById("txtdata").innerText = content;

}

当您在 Windows 10 中运行一个源应用时(我们正在运行我们在 Recipe 10.2 中开发的另一个应用),您会看到如图 10-11 所示的屏幕。

A978-1-4842-0719-2_10_Fig11_HTML.jpg

图 10-11。

Share charm windows showing the target app

如图 10-11 所示,app 10.6 _ 接收分享数据列在 app 的分享魅力分享目标列表中。当您选择应用时,您会看到从源应用共享的数据(标题、描述和文本),如图 10-12 中突出显示的。

A978-1-4842-0719-2_10_Fig12_HTML.jpg

图 10-12。

Share Charm windows showing the target app

10.7 接收其他应用共享的图像

问题

你需要开发一个功能,允许用户接收另一个 Windows 10 应用共享的图像。

解决办法

使用shareOperation.data.getBitmapAsync接收其他应用共享的图像。

它是如何工作的

源应用也可以与其他应用共享图像,如你在 Recipe 10.4 中看到的。为了共享位图图像,源应用使用request.data.setBitmap(imageStream)方法,通过传递图像流将位图图像设置为正在共享的请求对象。

为了接收位图图像,目标应用使用数据包视图的shareOperation.data.getBitmapAsync()方法。接收位图图像的完整代码如下所示:

// ShareOperation object in initiliaze with the eventObject event arugment

shareOperation = eventObject.detail.shareOperation;

if (shareOperation.data.contains(Windows.ApplicationModel.DataTransfer.StandardDataFormats.bitmap)) {

shareOperation.data.getBitmapAsync().done(function (bitmapStreamReference ) {

bitmapStreamReference.openReadAsync().done(function (bitmapStream) {

if (bitmapStream) {

document.getElementById("imageHolder").src = URL.createObjectURL(bitmapStream, { oneTimeOnly: true });

}

}, function (e) {

displayError("Bitmap: ", "Error reading image stream:  " + e);

});

}, function (e) {

displayError("Bitmap: ", "Error retrieving data: " + e);

});

}

这段代码首先检查shareOperation对象是否包含位图图像。然后它调用getBitmapAsync()方法从请求对象接收图像。最后,在异步调用的成功方法中,调用另一个对bitmapStreamReference.openReadAsync()的异步调用来读取流对象。openReadAsync返回流对象。然后,URL.createObjectURL(bitmapStream, { oneTimeOnly: true })行代码创建对象的 URL,然后将其分配给imageHolder作为 HTML img标签的源。

让我们在一个通用的 Windows 应用中实现这个事件,从其他应用接收位图。

在 Microsoft Visual Studio 2015 中使用 Windows 通用(空白应用)模板创建一个新项目。

首先,将下面的代码添加到default.html中。您需要用以下代码替换 body 标记:

<body class="win-type-body" style="background-color:white" >

<div>

<br /><br />

<div><p style="color:black">The following Data  was received from the source app:</p></div>

<br />

<h3 style="color:black">Data Properties</h3>

<strong style="color:black">Title: </strong><span id="txttitle" data-win-automationId="Title" style="color:black">(No title)</span><br />

<strong style="color:black">Description: </strong><span id="txtdescription" data-win-automationId="Description" style="color:black">(No description)</span><br />

<strong style="color:black">Data: </strong><span id="txtdata" data-win-automationId="Description" style="color:black">(No data)</span><br />

<div class="imageDiv">

<img class="imageHolder" id="imageHolder" alt="image holder" src="" />

</div>

</div>

</body>

现在,右键单击解决方案资源管理器中的项目,并选择添加➤新 JavaScript 文件。提供文件的名称。在本例中,我们将文件命名为 DataSharingDemo.js。

(function () {

"use strict";

function GetControl() {

WinJS.UI.processAll().done(function () {

// Initialize the activation handler

WinJS.Application.addEventListener("activated", activatedHandler, false);

});

}

document.addEventListener("DOMContentLoaded", GetControl);

})();

上述代码将一个激活的事件侦听器添加到 application 对象中。下面是名为activatedShareHandler的事件监听器函数。将这段代码添加到js文件中。

/// <summary>

/// Function to handle the activation

/// </summary>

/// <param name="eventArgs">

/// Arguments of the event. In the case of the Share contract, it has the ShareOperation

/// </param>

function activatedShareHandler(eventObject) {

// Check if the Share Contract was the cuase of this sharing

if (eventObject.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.shareTarget) {

eventObject.setPromise(WinJS.UI.processAll());

// ShareOperation object in initiliaze with the eventObject event arugment

shareOperation = eventObject.detail.shareOperation;

if (shareOperation.data.contains(Windows.ApplicationModel.DataTransfer.StandardDataFormats.bitmap)) {

shareOperation.data.getBitmapAsync().done(function (bitmapStreamReference) {

bitmapStreamReference.openReadAsync().done(function (bitmapStream) {

if (bitmapStream) {

document.getElementById("imageHolder").src = URL.createObjectURL(bitmapStream, { oneTimeOnly: true });

}

}, function (e) {

displayError("Bitmap: ", "Error reading image stream:  " + e);

});

}, function (e) {

displayError("Bitmap: ", "Error retrieving data: " + e);

});

}

}

}

最后,使用package.appxmanifest将该 app 声明为目标 app,如图 10-13 所示。

A978-1-4842-0719-2_10_Fig13_HTML.jpg

图 10-13。

Share Charm windows showing the target app

就是这样。现在,使用 Visual Studio 中的项目部署菜单部署应用。

您不必运行此应用来接收图像,因为这是注册的目标应用。Share charm 将此应用列为 Share charm 窗口中的目标应用,当用户从列表中选择该应用时,将为此应用激活一个新实例。激活的事件将被调用,然后接收源应用共享的图像。

10.8 共享自定义数据类型

问题

您需要开发一个允许用户共享自定义数据格式的特性,比如一个人的姓名和职务。

解决办法

如下使用request.data.setData功能:

request.data.setData("Schema", "ObjectName");

它是如何工作的

共享契约还允许开发人员构建应用来共享定制格式的数据,例如一本书(书名、出版商、作者姓名等)。)或一个人,带有姓名、职务、个人资料图片等属性。

Windows 10 通用 Windows 应用支持的自定义格式可以基于 http://schema.org 定义的模式,如 http://schema.org/personh ttp://schema.org/Book 。set data 方法接受以下两个参数:

request.data.setData("http://schema.org/Person

第一个参数是模式格式 id,第二个参数是对象本身。

让我们在一个通用的 Windows 应用中实现共享自定义数据。

在 Microsoft Visual Studio 2015 中使用 Windows 通用(空白应用)模板创建一个新项目。

首先,在default.html中添加以下代码。您需要用以下代码替换 body 标记:

<body class="win-type-body" style="background-color:white">

<div>

<p style="color:black">Enter Person  Name:</p>

<input class="text-box" id="txttitle" value="Name" size="40" />

<p style="color:black">Enter Person Title:</p>

<input class="text-box" id="txtjobtitle" value="Job Title" size="40" />

<p style="color:black">Enter telephone:</p>

<input class="text-box" id="txtphone" value="Telephone" size="40" />

<br />

<br />

</div>

</body>

现在,右键单击解决方案资源管理器中的项目,并选择添加➤新 JavaScript 文件。提供文件的名称。在本例中,我们将文件命名为 DataSharingDemo.js。

(function () {

"use strict";

function GetControl() {

WinJS.UI.processAll().done(function () {

var dataTransferManager = Windows.ApplicationModel.DataTransfer.DataTransferManager.getForCurrentView();

dataTransferManager.addEventListener("datarequested", shareDataHandler);

});

}

document.addEventListener("DOMContentLoaded", GetControl);

})();

通过复制以下代码实现shareDataHandler功能:

function shareDataHandler(e) {

var request = e.request;

;

// The request.data.properties.title is mandate

var name = document.getElementById("txttitle").value;

var person = {

"type": "http://schema.org/Person

"properties":

{

"name": name,

"jobtitle": document.getElementById("txtjobtitle").value

}

};

person = JSON.stringify(person);

request.data.properties.title = name;

request.data.properties.description = name;

request.data.setData("http://schema.org/Person

}

上述函数中的代码实现了自定义数据的共享。由于 schema.org 支持 JSON 和 XML 格式,因此person对象被定义为一个 JSON 字符串,用于设置姓名和职位等属性。

现在让我们创建另一个项目并实现代码来接收定制数据。

在 Microsoft Visual Studio 2015 中使用 Windows 通用(空白应用)模板创建一个新项目。

首先,将下面的代码添加到default.html中。您需要用下面的代码替换 body 标记。

<body class="win-type-body">

<textarea class="text-box" id="txtconent" rows="4" cols="50" />

<br />

<br />

</body>

现在,右键单击解决方案资源管理器中的项目,并选择添加➤新 JavaScript 文件。提供文件的名称。在本例中,我们将文件命名为 DataSharingDemo.js。

(function () {

"use strict";

function GetControl() {

WinJS.UI.processAll().done(function () {

// Initialize the activation handler

WinJS.Application.addEventListener("activated", activatedShareHandler, false);

});

}

document.addEventListener("DOMContentLoaded", GetControl);

})();

通过复制以下代码实现activatedShareHandler功能:

function activatedShareHandler(eventObject) {

if (eventObject.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.shareTarget) {

eventObject.setPromise(WinJS.UI.processAll());

// ShareOperation object is initiliaze with the eventObject event argument

shareOperation = eventObject.detail.shareOperation;

if (shareOperation.data.contains("http://schema.org/Person

shareOperation.data.getTextAsync("http://schema.org/Person").done(function.done(function)

var customFormatObject = JSON.parse(customFormatString);

if (customFormatObject) {

// This sample expects the custom format to be of typehttp://schema.org/Person

if (customFormatObject.type === "http://schema.org/Person

customFormatString = "Type: " + customFormatObject.type;

if (customFormatObject.properties) {

customFormatString += "\nName: " + customFormatObject.properties.name,

customFormatString += "\nNjobtitle: " + customFormatObject.properties.jobtitle;

}

}

}

document.getElementById("txtconent").value = customFormatString;

}, function (e) {

});

}

}

}

这段代码首先检查共享操作是否触发了事件。然后它初始化shareOperation = eventObject.detail.shareOperation。然后检查shareOperation.data.contains( http://schema.org/Person )。如果它包含一个 Person 对象,那么它调用shareOperation.data.getTextAsync方法来检索定制数据属性。在 success 方法中,它将 JSON 字符串解析为一个变量,如下所示:

var customFormatObject = JSON.parse(customFormatString);

最后,它读取这些属性并在文本区域显示出来。您需要使用 Visual Studio 部署选项来部署此应用。

现在运行共享自定义数据的应用。出现一个屏幕,如图 10-14 所示。

A978-1-4842-0719-2_10_Fig14_HTML.jpg

图 10-14。

The app UI that shares a custom data format

现在点击 Share charm 或者按下 Windows logo 键A978-1-4842-0719-2_10_Figc_HTML.jpg + H,当你从列表中选择 10.7B_ReceiveCustom_data app 时,你会看到如图 10-15 所示的屏幕。

A978-1-4842-0719-2_10_Fig15_HTML.jpg

图 10-15。

The receiver app for the custom data in the Share charm

当您选择应用时,会在 Share charm 窗口中显示接收者应用的用户界面,如图 10-16 所示。

A978-1-4842-0719-2_10_Fig16_HTML.jpg

图 10-16。

The receiver app with the received custom data

十一、后台任务

在任何应用中,您可能必须在后台静默执行某些任务。通用 Windows 平台提供了后台任务功能,允许您在后台运行代码。后台任务只不过是操作系统在后台运行的 JavaScript 文件。后台任务通常根据您可以订阅的系统触发器运行。需要在应用任务中声明一个后台任务。后台任务可以通过某些事件向应用报告进度、完成和取消。

11.1 后台任务的系统事件触发器

问题

您决定在应用中实现一个后台任务。您希望了解可以订阅的各种系统事件触发器,并在触发器发生时运行后台任务。

解决办法

系统事件通过一个名为SystemTrigger的全系统触发对象可用。当创建一个新的后台任务时,您需要让操作系统知道您想要订阅哪个系统触发器。您创建了一个新的SystemTrigger实例,并在构造函数中传递了触发器类型。触发类型在SystemTriggerType枚举中定义。表 11-1 列出了触发器及其描述。

表 11-1。

System Trigger Types

| 触发器名称 | 描述 | | --- | --- | | 互联网可用 | 互联网变得可用 | | 网络状态改变 | 网络发生了变化 | | OnlineIdConnectedStateChange | 与帐户更改相关联的在线 id | | SMS 接收器 | 接收到新的 SMS 消息 | | 时区变更 | 设备上的时区发生变化 |

11.2 创建和注册后台任务

问题

您希望为您的应用创建一个后台任务,并将其注册到操作系统。

解决办法

使用在Windows.ApplicationModel.Background名称空间中找到的BackgroundTaskBuilder创建一个新的后台任务并注册它。

它是如何工作的

Open Visual Studio 2015 Community edition. Select File ➤ New Project. In the New Project dialog window, select Templates ➤ JavaScript ➤ Windows ➤ Universal from the Installed Templates section (see Figure 11-1). Select Blank App (Universal Windows) from the available project templates. Provide a name and location for the app and click OK.

A978-1-4842-0719-2_11_Fig1_HTML.jpg

图 11-1。

New Project dialog   Visual Studio prepares the project, which will look like what’s shown in Figure 11-2 once done.

A978-1-4842-0719-2_11_Fig2_HTML.jpg

图 11-2。

Solution Explorer   Create a new JavaScript file in your js folder. Let’s name the file mytask.js. This js file contains the logic for the background work/task that you want to perform. You will use the file name of this js file to register the task, so keep note of the file name.   Here is the skeleton code of the mytask.js file: (function () { "use strict"; //gets the current instance of the background task var backgroundTaskInstance = Windows.UI.WebUI.WebUIBackgroundTaskInstance.current; var canceled = false,     settings = Windows.Storage.ApplicationData.current.localSettings,     key = backgroundTaskInstance.task.name; backgroundTaskInstance.addEventListener("canceled", OnCanceled); //checking if the background task is cancelled by the user. if (!canceled) {     doWork(); } else {     settings.values[key] = "Canceled";     close(); }     //the function which performs the main work as part of our background task function doWork() {     settings.values[key] = "Starting"     //Your code to do work in the background     //...     settings.values[key] = "Succeeded";     settings.values[key] = "Closing";     //call close when task is done     close(); } function OnCanceled(sender, reason) {     canceled = true; } })();

让我们检查一下代码。使用WebUIBackgroundTaskInstance.current属性获得后台任务的一个实例。然后,将取消的事件处理程序附加到后台任务的取消。然后定义一个doWork()函数,它作为后台任务的一部分完成实际工作。您使用localSettings并更新任务的状态,以便主应用可以读取相同的状态并在 UI 上执行任何更新。注意对close()函数的调用;后台任务应该在完成工作后调用这个函数。接下来,注册刚刚创建的任务。

In default.js, once the app has been activated, register the mytask.js background task that you just created. The following are the steps involved in registering a task. Iterate over all the tasks using the BackgroundTaskRegistration.allTasks property. It is important to check if your task is already registered or not. If you don’t check for this and register blindly, the background task is registered multiple times, which may lead to unexpected results. Here is the code snippet to do this: var task = null,   taskRegistered = false,   background = Windows.ApplicationModel.Background,   iter = background.BackgroundTaskRegistration.allTasks.first(); while (iter.hasCurrent) {     task = iter.current.value;     if (task.name === exampleTaskName) {         taskRegistered = true;         break;     }     iter.moveNext(); }   If the task is not already registered, perform the registration by using the BackgroundTaskBuilder class. You need to set the system trigger on which the task should be invoked. In this example, you listen to timeZoneChange as the trigger for the background task. Here is the code snippet: if (taskRegistered != true) {      var builder = new      Windows.ApplicationModel.Background.BackgroundTaskBuilder();      var trigger = new Windows.ApplicationModel.Background.SystemTrigger( Windows.ApplicationModel.Background.SystemTriggerType.timeZoneChange, false);      builder.name = exampleTaskName;      builder.taskEntryPoint = "js\\mytask.js";      builder.setTrigger(trigger);      task = builder.register(); }   Next, you need to handle the task completion. Add a completed event handler on the task itself. Here is the code snippet: task.addEventListener("completed", function (args) {         var settings = Windows.Storage.ApplicationData.current.localSettings;         var key = args.target.name;      settings.values[key] = "Completed"; });   Here is the complete code snippet for registering the background task: app.onactivated = function (args) {         if (args.detail.kind === activation.ActivationKind.launch) {                 if (args.detail.previousExecutionState !==         activation.ApplicationExecutionState.terminated) {         var task = null,            taskRegistered = false,            background = Windows.ApplicationModel.Background,            iter = background.BackgroundTaskRegistration.allTasks.first();         while (iter.hasCurrent) {         task = iter.current.value;              if (task.name === exampleTaskName) {                         taskRegistered = true;                     break;                 }              iter.moveNext();         }        if (taskRegistered != true) {         var builder = new       Windows.ApplicationModel.Background.BackgroundTaskBuilder();         var trigger = new       Windows.ApplicationModel.Background.SystemTrigger( Windows.ApplicationModel.Background.SystemTriggerType.timeZoneChange, false);         builder.name = exampleTaskName;              builder.taskEntryPoint = "js\\mytask.js";              builder.setTrigger(trigger);              task = builder.register();         }        task.addEventListener("completed", function (args) {         var settings =          Windows.Storage.ApplicationData.current.localSettings;         var key = args.target.name;              settings.values[key] = "Completed";         });         } else {                 }                         args.setPromise(WinJS.UI.processAll());                 }         };   Next, you need to add a declaration for the background task in the application manifest file. Open the manifest file by double-clicking package.appxmanifest, which is in the root of the application.   Click the Declarations tab. Select Background Tasks from the available declarations drop-down list. Click the Add button to add a declaration.   In the Supported task types section, select System event.   In the App settings section, under the Start page entry, add js\mytask.js as the value.   Save the package manifest file.

使用前面的代码,您已经创建了一个自定义后台任务,并将其注册到操作系统中。您使用系统触发事件,即时区更改事件来运行任务。按 F5 运行应用,然后更改您系统的时区设置。时区一改变,就会触发后台任务。

11.3 设置运行后台任务的条件

问题

您希望创建并注册一个自定义后台任务。但是您希望后台任务仅在满足特定条件时运行;例如,用户在场或用户不在场,等等。

解决办法

后台任务仅在触发 set 触发器时运行。正如在前面的配方中看到的,您在创建任务时提供了触发器。如果您的任务需要满足某个条件,即使在系统触发器被触发之后,您也可以创建一个系统条件,并在任务注册期间将该条件提供给任务生成器。使用SystemConditionType枚举提供条件。表 11-2 描述了 UWP 上可用的系统条件类型。

表 11-2。

System Condition Types

| 触发器名称 | 价值 | 描述 | | --- | --- | --- | | 病人 | Zero | 不是有效的条件类型 | | 用户呈现 | one | 只有当用户在场时,任务才能运行 | | 用户不存在 | Two | 只有当用户不在场时,任务才能运行 | | 互联网可用 | three | 任务只能在 Internet 可用时运行 | | 互联网不可用 | four | 任务只能在互联网不可用时运行 | | 会话连接 | five | 仅当连接了用户会话时,任务才能运行 | | 会话断开连接 | six | 仅当用户会话断开时,任务才能运行 | | 免费网络可用 | seven | 任务只能在免费网络(非计量)可用时运行 | | 背景工作成本 | eight | 仅当后台工作的成本较低时,任务才能运行 |

它是如何工作的

让我们学习如何为任务设置系统条件。

Create a SystemCondition object. Before registering a task, the condition to apply for the background task to run needs to be built. You need to create a SystemCondition object to represent the condition. The constructor of the SystemCondition object expects the SystemConditionType enumeration value, which is the condition that needs to be met before running the task. Here is the code snippet for providing the condition: var internetConditionType = Windows.ApplicationModel.Background.SystemConditionType.InternetAvailable; var internetCondition = new Windows.ApplicationModel.Background.SystemCondition(internetConditionType);   Add the SystemCondition object to background task. Once you have built the system condition, the next step is to add it to the task builder. BackgroundTaskBuilder provides an AddCondition() method that is used to set the condition. Here is the code snippet for adding the condition: taskBuilder.AddCondition(internetCondition);   Next, you register the task using the Register() method of the TaskBuilder. Here is the code snippet for the task registration: var task = builder.Register();

11.4 监控后台任务进度和完成情况

问题

您有一个由您的应用创建和注册的后台任务。您希望在应用中监控任务的进度和完成情况。

解决办法

在系统中注册的任务会触发进度和完成事件。您的应用需要提供事件处理程序,并订阅任务公开的事件。

它是如何工作的

Handle the task completion. First, you need to create a function to attach to the Completion event of the background task. This function takes in a parameter of type BackgroundTaskCompletedEventArgs. Here is the skeleton of the function: function onCompleted(args){         //code to deal with the completion of the task }   Next, you need to register the function with the background task. Here is the code snippet to do that: task = builder.register(); task.addEventListener("completed",onCompleted);   Put any code that needs to be executed upon task completion in the onCompleted function.   Handle the task progress. Similar to the completion event, a task fires a progress event too. You need to write a function that can be used to attach to the progress event of the background task. By subscribing to the progress event, any time a progress event is fired by the task, the function attached to the event is called. Any progress reporting routine can be written in the function. The function takes in two parameters: an IBackgroundTaskRegistration object and a BackgroundTaskProgressEventArgs object. Here is the skeleton of the function that handles the progress event: function onProgress(task, args){         //add code to perform progress related routine here }   Next, you need to register the function with the progress event of the background task. Here is the code snippet to register the function: task = builder.register(); task.addEventListener("progress", onProgress);

十二、Windows 应用中的位置和地图

构建 Windows 应用的开发人员可以利用 Windows 设备的功能将位置和地图集成到他们的应用中。在这一章中,你将看到如何在通用 Windows 运行时应用中使用位置 API 的方法。

12.1 获取当前位置

问题

你不知道你在哪里。Windows 应用需要确定并显示您的当前位置。

解决办法

使用在Windows.Devices.Geolocation命名空间中定义的Geolocator类的getGeopositionAsync方法,从 Windows 10 支持的设备中获取当前位置。

它是如何工作的

Create a new Universal Windows project using the Universal Windows template, which can be found under the JavaScript ➤ Windows ➤ Universal node of the New Project dialog in Microsoft Visual Studio 2015. This creates a single project in the Visual Studio Solution with the necessary files in it to start with.   The first step to integrate the location functionality in the app is to declare the Location capability in the package.appxmanifest file of the project. From Visual Studio Solution Explorer, double-click the package.appxmanifest file. In the GUI designer, click the Capabilities tab and select Location, as shown in Figure 12-1.

A978-1-4842-0719-2_12_Fig1_HTML.jpg

图 12-1。

Capabilities tab in Visual Studio   Open the project default.html file and add the following code under the body tag of each file: <div>     <p>Get the Current Location</p>     <br />     <button id="btnLocation">Get Location</button> <br /> </div> <br /> <div>     <table>         <tr>             <td>                 Latitude             </td>             <td >                 <div id="latitude">                 </div>             </td>         </tr>         <tr>             <td>                 Longitude             </td>             <td>                 <div id="longitude">                 </div>             </td>         </tr>         <tr>             <td>                 Accuracy             </td>             <td>                 <div id="accuracy">                 </div>             </td>         </tr>     </table> </div>   Open default.js (/js/default.js) in the project and replace the code in the file with the following: // For an introduction to the Blank template, see the following documentation: // http://go.microsoft.com/fwlink/?LinkID=392286 (function () {     "use strict";     var app = WinJS.Application;     var activation = Windows.ApplicationModel.Activation;     app.onactivated = function (args) {         if (args.detail.kind === activation.ActivationKind.launch) {             if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {             } else {             }             args.setPromise(WinJS.UI.processAll().                done(function ()                {                    // Add an event handler to the button.                    document.querySelector("#btnLocation").addEventListener("click",                        getLocation);                }));         }     };     var geolocation = null;     function getLocation()     {         if (geolocation == null) {             geolocation = new Windows.Devices.Geolocation.Geolocator();         }         if (geolocation != null) {             geolocation.getGeopositionAsync().then(getPosition);         }     }     function getPosition(position)     {         document.getElementById('latitude').innerHTML = position.coordinate.point.position.latitude;         document.getElementById('longitude').innerHTML = position.coordinate.point.position.longitude;         document.getElementById('accuracy').innerHTML = position.coordinate.accuracy;     }     app.oncheckpoint = function (args) {     };     app.start(); })(); The document.querySelector is used to add the click event handler for the btnLocation element. Upon click of the button, the getLocation method is called.   To get the current location information, create an instance of the Geolocator class defined in the Windows.Devices.Geolocation namespace and then invoke the getGeopositionAsync method of the Geolocator class. Once the location is retrieved, an action method needs to be defined to perform a certain set of actions. The getPosition method, as shown in the preceding code snippet, takes care of this. The parameter position is of type Geolocation, which can be used to get the current location information like latitude, longitude, accuracy, and so forth. The next step is to build the project and run it in the emulator or local machine.   Choose the Build menu and select Build Solution from Visual Studio to build the project. Select Mobile Emulator from the Run drop-down menu in the Visual Studio standard toolbar.   When you run the app for the first time on Windows, you are prompted to confirm if it is OK to use your location. Click Allow so that the app can use the location.   In the application, click the Get Location button to display the current location’s latitude and longitude, as shown in Figure 12-2.

A978-1-4842-0719-2_12_Fig2_HTML.jpg

图 12-2。

Current location in Windows Mobile app   When you click the app on the local machine, you are prompted with a message, as shown in Figure 12-3. Click the Allow button. This displays the current location (see Figure 12-4).

A978-1-4842-0719-2_12_Fig4_HTML.jpg

图 12-4。

Current location in a Windows desktop family app

A978-1-4842-0719-2_12_Fig3_HTML.jpg

图 12-3。

Allow current location prompt in Windows desktop family app   Note

确保在您的 Windows 设备中启用了定位服务,以获取当前位置。

12.2 响应地理定位器位置更新

问题

您希望经常检查应用中的位置是否有任何变化。

解决办法

使用在Windows.Devices.Geolocation名称空间中定义的Geolocator类的getGeopositionAsync方法。订阅PositionChangedLocationChanged事件,跟踪位置变化,并通过 Windows Mobile 或桌面系列应用做出响应。

它是如何工作的

Create a new Universal Windows project using the Universal Windows template, which can be found under JavaScript ➤ Windows ➤ Universal node of the New Project dialog in Microsoft Visual Studio 2015. This creates a single project in the Visual Studio Solution with the necessary files in it to start with.   Enable the Location capability in the package.appxmanifest file in the project.   Open the default.html file from Visual Studio Solution Explorer, and then add the following code under the body tag of each file. <div>     <button id="start">Start Tracking</button><br />     <br />     <button id="stop">Stop Tracking</button><br /> </div> <br /> <div>     <table>         <tr>             <td>                 Latitude             </td>             <td>                 <div id="latitude">                 </div>             </td>         </tr>         <tr>             <td>                 Longitude             </td>             <td>                 <div id="longitude">                 </div>             </td>         </tr>         <tr>             <td>                 Accuracy             </td>             <td>                 <div id="accuracy">                 </div>             </td>         </tr>         <tr>             <td>                 <div id="Status"></div>             </td>         </tr>     </table> </div> The preceding HTML code is similar to the code in the Recipe 12.1, but includes an additional div tag to display the status.   Open default.js (/js/default.js) in the project from Visual Studio Solution Explorer and replace the code in the file with the following: (function () {     "use strict";     var app = WinJS.Application;     var activation = Windows.ApplicationModel.Activation;     app.onactivated = function (args) {         if (args.detail.kind === activation.ActivationKind.launch) {             if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {             } else {             }             args.setPromise(WinJS.UI.processAll().                  done(function () {                      // Add an event handler to the button.                      document.querySelector("#start").addEventListener("click",                          Starttracking);                      // Add an event handler to the button.                      document.querySelector("#stop").addEventListener("click",                          Stoptracking);                  }));         }     };     var geolocation = null;     // Start tracking     function Starttracking() {         if (geolocation == null)         {             geolocation = new Windows.Devices.Geolocation.Geolocator();             geolocation.reportInterval = 100;         }         if (geolocation != null)         {             geolocation.addEventListener("positionchanged", onPositionChanged);             geolocation.addEventListener("statuschanged", onStatusChanged);         }     }     // On change of location position , update the UI     function onPositionChanged(args) {         document.getElementById('latitude').innerHTML = args.position.coordinate.point.position.latitude;         document.getElementById('longitude').innerHTML = args.position.coordinate.point.position.longitude;         document.getElementById('accuracy').innerHTML = args.position.coordinate.accuracy;     }     // Stop the tracking     function Stoptracking()     {         if (geolocation != null) {             geolocation.removeEventListener("positionchanged", onPositionChanged);         }     }     // event handler for the Status Changed method.     function onStatusChanged(args) {         var Status = args.status;         document.getElementById('Status').innerHTML =             getStatus(Status);     }     // Gets the status     function getStatus(Status) {         switch (Status) {             case Windows.Devices.Geolocation.PositionStatus.ready:                 return "Ready";                 break;             case Windows.Devices.Geolocation.PositionStatus.initializing:                 return "Initializing";                 break;             case Windows.Devices.Geolocation.PositionStatus.disabled:                 return "Location is disabled . Check the Location settings in your device or Appxmanifest file";                 break;             case Windows.Devices.Geolocation.PositionStatus.notInitialized:                 return "Not Initialized";             default:                 return "Status us unknown";         }     }     app.oncheckpoint = function (args) {     };     app.start(); })(); The first step is to add the click event handler for the Start Tracking and the Stop Tracking buttons. The document.querySelector is used to add the event listener. document.querySelector("#start").addEventListener("click",Starttracking); document.querySelector("#stop").addEventListener("click",Stoptracking); A new instance of the Geolocator class is created in the Starttracking method and the reportInterval is set. The reportInterval defines the minimum time interval between location updates, in milliseconds. geolocation = new Windows.Devices.Geolocation.Geolocator(); geolocation.reportInterval = 100; The positionchanged and the statuschanged event listeners are added to the geolocation instance: geolocation.addEventListener("positionchanged", onPositionChanged); geolocation.addEventListener("statuschanged", onStatusChanged); The positionchanged event is raised when there is a change in location. The statuschanged event is raised when the ability of the Geolocator to provide updated location changes; for example, if the location is disabled or initialized, and so forth. The getStatus method returns the message based on the Windows.Devices.Geolocation.PositionStatus. When you don’t need to track the location, just remove the positionchanged event listener, as follows: geolocation.removeEventListener("positionchanged", onPositionChanged);   Now, build and run the project in the emulator.   In the app, click the Start Tracking button. The app subscribes for the location updates via the Geolocator’s Onpositionchanged event and displays the location information (see Figure 12-5).

A978-1-4842-0719-2_12_Fig5_HTML.jpg

图 12-5。

Location updates using the Windows Mobile emulator’s additional tools When the app is run on Windows desktop using the Local Machine option, you should see the screen shown in Figure 12-6.

A978-1-4842-0719-2_12_Fig6_HTML.jpg

图 12-6。

Location updates in Windows desktop using Local Machine option   Note

Windows Mobile 模拟器提供了额外的工具,让开发者在开发过程中测试基于位置的应用,如图 12-5 所示。

12.3 用 HTML5 检测用户的位置

问题

你不知道你在哪里。Windows 应用需要确定并显示您的当前位置。

解决办法

除了 Windows 运行时 API,WinJS 应用还可以利用 W3C 地理位置 API,通过使用 Windows 应用中的 HTML5 来检测用户的当前位置。

它是如何工作的

Create a new Universal Windows project using the Universal Windows template, which can be found under JavaScript ➤ Windows ➤ Universal node of the New Project dialog in Microsoft Visual Studio 2015. This creates a single project in the Visual Studio Solution with the necessary files in it to start with.   The first step to integrate the location functionality in the app is to declare the Location capability in the package.appxmanifest file of the Windows app. From Visual Studio Solution Explorer, double-click the package.appxmanifest file. In the GUI designer, click the Capabilities tab and select Location.   Open the default.html file of the Windows app and add the following code under the body tag of the file. <h1>Current Location using HTML5</h1> <button id="btnLocation">Get Location</button> <br /> <label>Latitude</label> <div id="latitude"></div><br /> <label>Longitude</label> <div id="longitude"> </div><br /> <div id="status"> </div><br />   Open default.js (/js/default.js) in the project. Replace the code in the file with the following: (function () {     "use strict";     var app = WinJS.Application;     var activation = Windows.ApplicationModel.Activation;     app.onactivated = function (args) {         if (args.detail.kind === activation.ActivationKind.launch) {             if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {             } else {             }             args.setPromise(WinJS.UI.processAll().                  done(function () {                      // Add an event handler to the button.                      document.querySelector("#btnLocation").addEventListener("click",                          GetLocation);                  }));         }     };     var nav = null;     function GetLocation() {         if (nav == null) {             nav = window.navigator;         }         var geoloc = nav.geolocation;         if (geoloc != null) {             geoloc.getCurrentPosition(Onsuccess, Onerror);         }     }     // after getting the location information     function Onsuccess(position) {         document.getElementById("latitude").innerHTML =             position.coords.latitude;         document.getElementById("longitude").innerHTML =             position.coords.longitude;     }     // On error when trying to get the location     function Onerror(error) {         var errorMessage = "";         switch (error.code) {             case error.PERMISSION_DENIED:                 errorMessage = "Location is disabled";                 break;             case error.POSITION_UNAVAILABLE:                 errorMessage = "Data unavailable";                 break;             case error.TIMEOUT:                 errorMessage = "Timeout error";                 break;             default:                 break;         }         document.getElementById("status").innerHTML = errorMessage;     }     app.oncheckpoint = function (args) {     };     app.start(); })();   Add the click event handler for the Get Location button. The document.querySelector is used to get the button control, and the addEventListener method is used to add the click event and map it to the GetLocation method. document.querySelector("#btnLocation").addEventListener("click",                          GetLocation); The getCurrentPosition method of the window.navigator.geolocation class is used to get the user’s current location. if (nav == null) {             nav = window.navigator;         }         var geoloc = nav.geolocation;         if (geoloc != null) {             geoloc.getCurrentPosition(Onsuccess, Onerror);         } Once the current position is successfully retrieved, the control is passed to the Onsuccess method to process the coordinates and display it. On an error, the Onerror method is invoked, which displays the error message in case of an issue getting the location information.   Build and run the project on the local machine.   Click the Get Location button in the app, as shown in Figure 12-7. The app immediately prompts the user to allow the app to use the location API. Once you click Allow, you should immediately see the latitude and the longitude of the current location.

A978-1-4842-0719-2_12_Fig7_HTML.jpg

图 12-7。

Current location in Windows Store app using HTML5   Note

W3C 地理定位 API 目前仅适用于 Windows 桌面设备系列应用。当您在 Windows Mobile 仿真程序上运行相同的时,状态显示为禁用。

12.4 使用 HTML5 检测位置更新

问题

您希望经常检查应用中的位置是否有任何变化。

解决办法

您可以使用 HTML5 中的 W3C 地理定位 API 来检测 Windows 应用中的位置变化。

它是如何工作的

Create a new Universal Windows project using the Universal Windows template, which can be found under JavaScript ➤ Windows ➤ Universal node of the New Project dialog in Microsoft Visual Studio 2015. This creates a single project in the Visual Studio Solution with the necessary files in it to start with.   The first step to integrate the location functionality in the app is to declare the Location capability in the package.appxmanifest file of the Windows app. From Visual Studio Solution Explorer, double-click the package.appxmanifest file. In the GUI designer, click the Capabilities tab and check Location.   Open the default.html file of the Windows app and add the following code under the body tag of the file: <h1>Current Location using HTML5</h1> <button id="btnstart">Start</button> <button id="btnstop">Stop</button> <br /> <label>Latitude</label> <div id="latitude"></div><br /> <label>Longitude</label> <div id="longitude"> </div><br /> <div id="status"> </div><br />   Open default.js (/js/default.js) in the Windows project and replace the code in the file with the following: (function () {     "use strict";     var app = WinJS.Application;     var activation = Windows.ApplicationModel.Activation;     app.onactivated = function (args) {         if (args.detail.kind === activation.ActivationKind.launch) {             if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {             } else {             }             args.setPromise(WinJS.UI.processAll().                 done(function () {                     document.querySelector("#btnstart").addEventListener("click",                         starttracking);                     document.querySelector("#btnstop").addEventListener("click",                         stoptracking);                 }));         }     };     var geolocation = null;     var positionInstance;     // on click of the start tracking     function starttracking() {         if (geolocation == null) {             geolocation = window.navigator.geolocation;         }         if (geolocation != null) {             positionInstance = geolocation.watchPosition(onsuccess, onerror);         }     }     // on click of the stop tracking button     function stoptracking() {         geolocation.clearWatch(positionInstance);     }     // on success of getting the location     function onsuccess(pos) {         document.getElementById('latitude').innerHTML = pos.coords.latitude;         document.getElementById('longitude').innerHTML = pos.coords.longitude;     }     // On error when trying to get the location     function Onerror(error) {         var errorMessage = "";         switch (error.code) {             case error.PERMISSION_DENIED:                 errorMessage = "Location is disabled";                 break;             case error.POSITION_UNAVAILABLE:                 errorMessage = "Data unavailable";                 break;             case error.TIMEOUT:                 errorMessage = "Timeout error";                 break;             default:                 break;         }         document.getElementById("status").innerHTML = errorMessage;     }     app.oncheckpoint = function (args) {     };     app.start(); })();   Add the click event handler for the Start Tracking and Stop Tracking buttons. The document.querySelector is used to get the button control and the addEventListener method is used to add the click event to the tracking buttons. The tracking is handled by the watchPosition method of the window.navigator.geolocation class, as follows: if (geolocation == null) {             geolocation = window.navigator.geolocation; } if (geolocation != null) {             positionInstance = geolocation.watchPosition(onsuccess, onerror); } When the coordinates are retrieved, the Onsuccess method is invoked, which is used to process the result and display it. When there is any issue getting the location, the Onerror method is invoked with the appropriate error code, which can be used by the developer to display a user-friendly message for each error code. To stop the track, the clearWatch method of the geolocation needs to be called by providing the watchid parameter that was retrieved initially with the watchPosition function. geolocation.clearWatch(positionInstance);   Build and run the project on the local machine.   In the app, click the Start button. The app immediately prompts the user to allow the app to use the location API. Once you click Allow, you should immediately see the latitude and the longitude of the current location, and the tracking of the location begins, as shown in Figure 12-8.

A978-1-4842-0719-2_12_Fig8_HTML.jpg

图 12-8。

Detect location updates in Windows Store app using HTML5   Note

W3C 地理定位 API 目前仅适用于 Windows 桌面设备系列。Windows 10 Mobile 不支持它。

12.5 在内置地图应用中显示地图

问题

您希望在内置的地图应用中显示地图并标出位置。

解决办法

使用通用 Windows 应用中的bingmaps : URI 方案在内置地图应用中显示地图。

它是如何工作的

Create a new Universal Windows project using the Universal Windows template, which can be found under JavaScript ➤ Windows ➤ Universal node of the New Project dialog in Microsoft Visual Studio 2015. This creates a single project in the Visual Studio Solution with the necessary files in it to start with.   Open the default.html file from the project, and add the following code under the body tag of the file: <h1>Display Map</h1> <button id="btnDisplayMap">Display Map</button> <br />   Open default.js (/js/default.js) in the project and replace the code in the file with the following: (function () {     "use strict";     var app = WinJS.Application;     var activation = Windows.ApplicationModel.Activation;     app.onactivated = function (args) {         if (args.detail.kind === activation.ActivationKind.launch) {             if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {             } else {             }             args.setPromise(WinJS.UI.processAll().                   done(function () {                       // Add an event handler to the button.                       document.querySelector("#btnDisplayMap").addEventListener("click",                           DisplayMap);                   }));         }     }; // Method to display the Built-in Map.     function DisplayMap() {         var latitude = "12.917264";         var longitude = "77.634786";         var uri = "bingmaps:?cp="+ latitude + "∼" + longitude + "lvl=10";         Windows.System.Launcher.launchUriAsync(new Windows.Foundation.Uri(uri));     }     app.oncheckpoint = function (args) {     };     app.start(); })();

URI 计划可用于从您的 Windows 应用启动地图应用。LaunchUriAsync方法通常用于使用 URI 方案从 Windows 应用商店应用启动另一个应用。在这种情况下,bingmaps: URI 方案用于启动地图应用。

Note

使用LaunchUriAsync方法时,用户将被带到设备上的另一个应用,用户必须在使用地图应用后手动返回到您的应用。

开发者可以向 URI 方案提供适当的参数来显示位置,甚至在地图上显示路线。例如,以下 URI 方案打开 Bing 地图应用,并显示一幅以印度班加罗尔市为中心的地图:

Bingmaps:? Cp=12.917264∼77.634786

开发人员可以使用表 12-1 中所示的一些参数以及bingmaps: URI 方案。

表 12-1。

Examples of the Different Parameters Used with the bingmaps: URI

| 参数 | 例子 | | --- | --- | | 中心点 | cp=40.726966∼-74.006076 | | 边界框 | bb=39.719 至 74.52 至 41.71 至 73.5 | | q(查询术语或搜索术语) | q =墨西哥餐馆 | | 缩放级别 | 拉特=10.50 | | trfc(指定在地图中包含交通信息) | trfc=1 | | 路由协议 | rtp=adr。一个% 20 微软% 20 微软% 20 微软% 20 微软% 20 微软% 20 微软% 20 微软% 20 微软% |

Note

必应地图包含了很多参数;表 12-1 只显示了其中的几个。关于必应地图参数的更多信息可以在 http://msdn.microsoft.com/en-us/library/windows/apps/xaml/jj635237.aspx 找到。

A978-1-4842-0719-2_12_Fig9_HTML.jpg

图 12-9。

Built-in maps in the Windows Mobile app Now, build the project and run it. Click the Display Map button on the screen. If you are running the Windows app on the Windows Mobile emulator, you should see the built-in map with the location being plotted, as shown in Figure 12-9.

如果应用使用本地机器选项在 Windows 桌面上运行,地图应用会显示位置(参见图 12-10 )。

A978-1-4842-0719-2_12_Fig10_HTML.jpg

图 12-10。

Built-in maps in Windows desktop family Note

URI 方案是 Windows Phone 8.1 和更早版本中可用的 MapsTask 启动器的替代品。

12.6 在内置地图应用中显示方向

问题

您希望在 Windows 设备的内置地图应用中显示从一个位置到另一个位置的方向或路线。

解决办法

带有rtp参数的bingmaps : URI 方案可以在您的 Windows 应用中使用,以在内置的地图应用中显示地图,以及显示从一个位置到另一个位置的点对点驾驶方向。

它是如何工作的

Create a new Universal Windows project using the Universal Windows template, which can be found under JavaScript ➤ Windows ➤ Universal node of the New Project dialog in Microsoft Visual Studio 2015. This creates a single project in the Visual Studio Solution with the necessary files in it to start with.   Open the default.html file from the project using Visual Studio Solution Explorer, and add the following code under the body tag of each file: <h1>Display Map</h1> <button id="btnDisplayRoute">Display Route</button> <br />   Open default.js (/js/default.js) in the project and replace the code in the file with the following: (function () {     "use strict";     var app = WinJS.Application;     var activation = Windows.ApplicationModel.Activation;     app.onactivated = function (args) {         if (args.detail.kind === activation.ActivationKind.launch) {             if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {             } else {             }             args.setPromise(WinJS.UI.processAll().                  done(function () {                      // Add an event handler to the button.                      document.querySelector("#btnDisplayRoute").addEventListener("click",                          DisplayRoute);                  }));         }     };     function DisplayRoute() {         var fromAddress = "adr.HSR Layout 5th sector, Bangalore";         var toAddress = "adr.Microsoft India,Signature Building,Bangalore";         var uri = "bingmaps:?rtp=" + fromAddress + "∼"+ toAddress;         Windows.System.Launcher.launchUriAsync(new Windows.Foundation.Uri(uri));         //Windows.Services.Maps.MapManager.showDownloadedMapsUI()     }     app.oncheckpoint = function (args) {     };     app.start(); })();

URI 计划可用于从 Windows 应用中启动地图应用。LaunchUriASync方法通常用于使用 URI 方案从 Windows 应用启动另一个应用。在这种情况下,带有rtp参数的bingmaps: URI 方案用于启动内置地图,然后显示从指定地址到指定位置的行驶方向。

Note

使用LaunchUriAsync方法时,用户被带到设备上的另一个 app 用户在使用地图应用后,必须手动返回到您的应用。

开发人员可以将trfc=1参数与 URI 一起显示交通信息。

"bingmaps:?rtp=adr.HSR Layout 5th sector, Bangalore∼adr.Microsoft India,Signature Building,Bangalore&trfc=1";

在前面的 URI 方案中,adr.定义了地址。rtp需要两个路径点来寻找路线。提供trfc参数也是为了显示交通信息。

A978-1-4842-0719-2_12_Fig11_HTML.jpg

图 12-11。

Directions in Windows Mobile Build the project and run it. Click the Display Map button on the screen. If you are running the Windows app on a Windows Mobile emulator, you should see the built-in map with the location being plotted, as shown in Figure 12-11.

如果 Windows 应用在桌面系列上运行,地图应用用于显示位置,如图 12-12 所示。

A978-1-4842-0719-2_12_Fig12_HTML.jpg

图 12-12。

Directions in Windows app Note

URI 方案是 Windows Phone 8 中 MapsDirectionsTask 启动器的替代品。

12.7 Windows 应用商店应用中的 Bing 地图控件

问题

您希望在 Windows 应用中使用地图,而不是启动内置地图应用。

解决办法

使用 Bing Maps AJAX Control 7.0 在使用 WinJS 开发的通用 Windows 应用中添加地图功能。

它是如何工作的

Bing 地图是微软提供的在线地图服务,允许用户使用微软的地图解决方案并利用 Bing 地图的各种功能。Bing Maps AJAX Control 7.0 和 Bing Maps REST 服务为开发人员提供了独特的机会,可以轻松地将位置和搜索功能纳入他们的移动和 web 应用。

要使用 Bing Maps AJAX Control 7.0,请按照下列步骤操作:

Download and install the Bing Maps SDK for Windows Store apps (for Windows 8.1, which also works for Windows 10) from http://go.microsoft.com/fwlink/?LinkID=322092 .   Get the Bing Maps key. Go to the Bing Maps Account Center at https://www.bingmapsportal.com and create a key for the application. You have to use this key in the Windows Store app.   Create a new project using the Windows Store app template in Microsoft Visual Studio 2013, which creates a Windows Store app.   Add the reference of the Bing Maps for JavaScript to the project. In Solution Explorer, right-click the project references and select Add Reference and Bing Maps for JavaScript. Click OK, as shown in Figure 12-13.

A978-1-4842-0719-2_12_Fig13_HTML.jpg

图 12-13。

Reference Manager in Visual Studio for Bing Maps   Open the default.html file in the project and add the following code in the body tag of the file: <div id="myMap"></div>   In the default.html file, also add the reference to the Bing Maps JavaScript files: <!-- Bing Maps references -->     <script type="text/javascript" src="ms-appx:///Bing.Maps.JavaScript//js/veapicore.js"></script>     <script type="text/javascript" src="ms-appx:///Bing.Maps.JavaScript//js/veapimodules.js"></script>   Open default.js (/js/default.js) and replace the code in the file with the following: (function () {     "use strict";     var app = WinJS.Application;     var activation = Windows.ApplicationModel.Activation;     app.onactivated = function (args) {         if (args.detail.kind === activation.ActivationKind.launch) {             if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {             } else {             }             args.setPromise(WinJS.UI.processAll().                 done(function () {                     Microsoft.Maps.loadModule('Microsoft.Maps.Map', { callback: GetMap });                 }));         }     };     var map;     function GetMap() {         //   Microsoft.Maps.loadModule('Microsoft.Maps.Map', { callback: GetMap });         var loc = new Microsoft.Maps.Location(13.0220, 77.4908);         // Initialize the map         map = new Microsoft.Maps.Map(document.getElementById("myMap"), {             credentials: "Bing Map Key",             zoom: 10         });         var pin = new Microsoft.Maps.Pushpin(loc);         map.entities.push(pin);         // Center the map on the location         map.setView({ center: loc, zoom: 10 });     }     app.oncheckpoint = function (args) {     };     app.start(); })(); The loadModule of the Microsoft.Maps function needs to be called first to load the map. loadModule has an optional culture parameter that can be used to identify the localized language and the region. The GetMap callback function is specified for loadModule. Microsoft.Maps.loadModule('Microsoft.Maps.Map', { callback: GetMap }); An instance of the Microsoft.Maps.Map is created by specifying the container div element and the Bing Map API key. // Initialize the map map = new Microsoft.Maps.Map(document.getElementById("myMap"), {     credentials: "Bing Map API Key", }); The location on the map where the pushpin is to be added is identified using the map.entities.push method. var loc = new Microsoft.Maps.Location(13.0220, 77.4908); var pin = new Microsoft.Maps.Pushpin(loc); map.entities.push(pin); Finally, the map is displayed by setting the location at the center and with a zoom level value of 10.   Build the application and run it in the Windows emulator. You should be able to view the map and the pushpin added to the map, as shown in Figure 12-14.

A978-1-4842-0719-2_12_Fig14_HTML.jpg

图 12-14。

Bing Maps in Windows app

Bing Maps AJAX 控件提供了额外的 API,允许开发人员集成额外的地图功能,如显示交通信息、方向等。

目前,WinJS 库没有在 SDK 中提供现成的地图控件,因此 Bing Maps AJAX 控件是一个很好的替代解决方案。

十三、构建连接到云的应用

Microsoft Azure Mobile Services 为开发人员提供了一种最简单的方式来将数据从 Windows 应用存储到云中的 SQL Azure 数据库。通过使用微软 Azure 移动服务,开发人员无需担心创建和托管他们自己的 web 服务。大部分事情都由微软 Azure 移动服务处理。

本章介绍了从通用 Windows 应用设置和使用 Microsoft Azure 移动服务进行数据存储和检索的一些方法。

13.1 在 Microsoft Azure 中创建新的移动服务

问题

你需要在 Microsoft Azure Mobile Services 中创建一个新的移动服务,供你的通用 Windows 应用使用。

解决办法

登录到 Microsoft Azure 管理门户,并使用移动服务部分创建新的移动服务。

它是如何工作的

Microsoft Azure 移动管理门户为开发人员管理各种资源(如虚拟机、移动服务、云服务等)提供了必要的选项。

按照以下步骤在 Microsoft Azure 中创建新的移动服务:

Log in to the Microsoft Azure Management portal by navigating to http://manage.windowsazure.com and providing your login credentials.   You can create a new mobile service by clicking the +New button in the bottom bar and then selecting Compute ➤ Mobile Service ➤ Create, as shown in Figure 13-1.

A978-1-4842-0719-2_13_Fig1_HTML.jpg

图 13-1。

Microsoft Azure dashboard for creating a new mobile service   Provide the details of the mobile service. This includes the URL to access the mobile service, subscription, region, back end, and so forth. You can provide the Mobile Service name as winjsrecipes. Currently, Microsoft Azure supports JavaScript and .NET back ends. Select JavaScript in this recipe and click the Next button, as shown in Figure 13-2.

A978-1-4842-0719-2_13_Fig2_HTML.jpg

图 13-2。

New Mobile Service dialog   If you selected Create a new SQL database instance, you have to provide the existing database settings information, as shown in Figure 13-3. Complete the mobile service creation.

A978-1-4842-0719-2_13_Fig3_HTML.jpg

图 13-3。

New Mobile Service database settings dialog   Within a few minutes, the mobile service is ready and displayed in the Mobile Service overview screen.

您还可以使用 Visual Studio 2015 在 Microsoft Azure 中创建移动服务。若要从 Visual Studio 2015 创建移动服务,请按照下列步骤操作:

Launch Visual Studio 2015 and open the Server Explorer window.   In the Server Explorer window, right-click Azure and select Connect to Microsoft Azure… in the context menu, as seen in Figure 13-4. Provide your Microsoft Azure login credentials. This imports the Azure subscription to Visual Studio.

A978-1-4842-0719-2_13_Fig4_HTML.jpg

图 13-4。

Connect to Azure from the Visual Studio Server Explorer window   The next step is to create the mobile service from Server Explorer. Right-click Mobile Services and select Create Service, as demonstrated in Figure 13-5.

A978-1-4842-0719-2_13_Fig5_HTML.jpg

图 13-5。

Create a Service from Visual Studio 2015   In the Create Mobile Service dialog, provide the necessary information for the mobile service to be created, which includes the URL, region, database information, and so forth. Name the recipe winjs, as shown in Figure 13-6.

A978-1-4842-0719-2_13_Fig6_HTML.jpg

图 13-6。

New Mobile Service dialog in Visual Studio 2015   Note

您需要订阅 Microsoft Azure。如果你还没有订阅它,那么你需要访问 http://azure.microsoft.com/en-us/ 。如果你想试用微软 Azure,你可以获得一个免费试用帐户。

13.2 在移动服务中创建数据库表

问题

您需要创建一个表来存储 Microsoft Azure 中的待办事项,这些事项将由您的通用 Windows 应用使用。

解决办法

您可以使用 Microsoft Azure 管理门户或 Visual Studio 2015 在 Microsoft Azure 移动服务中创建数据库表。

它是如何工作的

A978-1-4842-0719-2_13_Fig7_HTML.jpg

图 13-7。

Azure Mobile Service dashboard To create a table from Microsoft Azure Mobile Services, log in to the Azure Management portal with your login credentials. In the Mobile Services overview screen, select the mobile service in which you would like to create a new table.   In the selected mobile service (see Figure 13-7), select the DATA tab and click ADD A TABLE to start creating a new table.

在 Create New Table 对话框中,输入表名(称之为 todo ),并让任何人拥有应用键的默认权限进行插入、更新、删除和读取操作,如图 13-8 所示。单击提交按钮。

A978-1-4842-0719-2_13_Fig8_HTML.jpg

图 13-8。

Table creation within the Mobile Services in Microsoft Azure

请注意,您没有为 todo 表指定列。一种方法是从仪表板向表中添加列,这是一种首选方法。另一种选择是使用动态模式,其中的列是根据您插入的数据动态创建的(这使得开发新的移动服务更加容易)。使用本食谱中的第二个选项。开发人员可以从仪表板禁用动态模式。

13.3 为 WinJS 客户端库安装移动服务

问题

您需要为您的 Windows 应用安装 WinJS 客户端库的移动服务,以便与 Microsoft Azure 移动服务进行交互。

解决办法

使用 NuGet 包管理器控制台在通用 Windows 项目中执行以下命令,将移动服务添加到 WinJS 客户端库:

Install-Package WindowsAzure.MobileServices.Winjs

它是如何工作的

NuGet 包管理器控制台允许开发人员快速安装库。要为 WinJS 客户端库添加移动服务,请按照下列步骤操作。

Launch Visual Studio 2015 and create a new Universal Windows app using the JavaScript template.   In Visual Studio, select Tools ➤ Library package manager ➤ Package Manager Console, and then enter the following command: install-package WindowsAzure.MobileServices.WinJS   Before running this command, ensure that the correct project is selected as Default project in the Package Manager Console (see Figure 13-9).

A978-1-4842-0719-2_13_Fig9_HTML.jpg

图 13-9。

Project selection in the Package Manager Console Once the installation is successful, you will see the new JavaScript files in the JS folder of the project in the Solution Explorer, as shown in Figure 13-10.

A978-1-4842-0719-2_13_Fig10_HTML.jpg

图 13-10。

Universal project in Solution Explorer after installation of library   To use the WinJS library for mobile services, you must add a reference to the MobileServices.min.js script in the HTML page. <script src="js/MobileServices.min.js"></script>

现在,您可以从 Windows 应用商店项目访问移动服务客户端库。

13.4 执行 CRUD 操作

问题

您需要从 Windows 应用的 todo 表中创建、读取、更新和删除(CRUD)记录。(todo 表的创建在前面的配方中已经演示过了。)

解决办法

通过使用通过移动服务库公开的方法,您可以对在移动服务中创建的表执行基本的 CRUD 操作。

它是如何工作的

在前一个配方中,您创建了一个名为winjsrecipes的移动服务和一个名为 todo 的表。在本菜谱中,您将探索如何从 Windows 应用中与 todo 数据库表进行交互。微软 Azure 移动服务:CRUD 操作:

Open the default.html page in the Windows app and add the following reference to the mobile service library head section: <script src="js/MobileServices.min.js"></script>   In the same file, add the following code to the body tag. <div style="margin:38px 18px 18px 18px">         <h4 style="margin-bottom:18px">winjsrecipes</h4>         <div>Enter some text below and click Save to insert a new TodoItem item into your database</div>         <input type="text" id="textInput" style="width:240px;vertical-align:middle;margin-right:10px;" />         <button id="buttonSave" style="vertical-align:middle">Save</button>         <div>Click refresh below to load the unfinished TodoItems from your database. Use the checkbox to complete and update your TodoItems</div>         <button id="buttonRefresh" style="width:100%">Refresh</button>         <div id="TemplateItem" data-win-control="WinJS.Binding.Template">             <input type="checkbox" style="margin-right:5px" data-win-bind="checked: complete; dataContext: this; innerText: text" />         </div>         <div id="listItems"              data-win-control="WinJS.UI.ListView"              data-win-options="{ itemTemplate: TemplateItem, layout: {type: WinJS.UI.ListLayout} }">         </div>     </div>   Open the default.js file from the JS folder and replace it with the following code: // For an introduction to the Blank template, see the following documentation: // http://go.microsoft.com/fwlink/?LinkID=392286 (function () {     "use strict";     var app = WinJS.Application;     var activation = Windows.ApplicationModel.Activation;     app.onactivated = function (args) {         if (args.detail.kind === activation.ActivationKind.launch) {             if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {             } else {             }             args.setPromise(WinJS.UI.processAll());             var client = new WindowsAzure.MobileServiceClient(                                 " https://winjsrecipes.azure-mobile.net/ ",                                 "<Application Key2>"                         );             var todoTable = client.getTable('todo');             var todoItems = new WinJS.Binding.List();             var insertTodoItem = function (todoItem) {                 todoTable.insert(todoItem).done(function (item) {                     todoItems.push(item);                 });             };             var refreshTodoItems = function () {                 todoTable.where({ complete: false })                     .read()                     .done(function (results) {                         todoItems = new WinJS.Binding.List(results);                         listItems.winControl.itemDataSource = todoItems.dataSource;                     });             };             var updateCheckedTodoItem = function (todoItem) {                 todoTable.update(todoItem).done(function (item) {                     todoItems.splice(todoItems.indexOf(item), 1);                 });             };             buttonSave.addEventListener("click", function () {                 insertTodoItem({                     text: textInput.value,                     complete: false                 });             });             buttonRefresh.addEventListener("click", function () {                 refreshTodoItems();             });             listItems.addEventListener("change", function (eventArgs) {                 var todoItem = eventArgs.target.dataContext.backingData;                 todoItem.complete = eventArgs.target.checked;                 updateCheckedTodoItem(todoItem);             });             refreshTodoItems();         }     };     app.oncheckpoint = function (args) {     };     app.start(); })();   Run the application on the Windows desktop using the Local Machine option. You should see screens like the ones shown in Figure 13-11. You should be able to add, delete, or update the data from your app to the mobile service.

A978-1-4842-0719-2_13_Fig11_HTML.jpg

图 13-11。

Windows app with insert and refresh options

在从 Windows 应用对 Microsoft Azure Mobile Services 执行任何操作之前,您必须首先连接到该服务并获得对远程服务的访问权限。使用MobileServiceClient对象可以访问远程服务客户端。类似地,通过使用MobileServiceTable对象可以访问远程表。

下面是如何获得MobileServiceClient和表引用:

var client = new WindowsAzure.MobileServiceClient(

"https://winjsrecipes.azure-mobile.net/

"<Enter the Application Key>"

);

var todoTable = client.getTable('todo');

MobileServiceClient构造器接受两个参数。第一个参数是移动服务的 URL,第二个参数是应用密钥。

Note

若要获取您的移动服务的应用密钥,您需要登录到 Microsoft Azure 管理门户,导航到您的移动服务的仪表板,并使用“管理密钥”选项获取应用密钥。您需要使用这个键作为移动服务客户端的第二个参数。

插入操作可以通过调用MobileServiceTable对象的insert方法来执行。以下代码将新文本插入 todo 表中:

insertTodoItem({

text: textInput.value,

complete: false

});

var insertTodoItem = function (todoItem) {

// This code inserts a new TodoItem into the database. When the operation completes

todoTable.insert(todoItem).done(function (item) {

todoItems.push(item);

});

};

insert方法的返回类型是承诺。您可以包含成功和错误函数来处理insert方法的操作结果。在前面的例子中,一旦插入成功,UI 中的todoItems列表就会更新。

移动服务中现有记录的更新可以通过使用在MobileServiceTable类中定义的update方法来执行。例如,下面演示了如何更新 todo 表中的记录:

var todoItem = { id:1 };

todoItem.complete = true;

updateCheckedTodoItem(todoItem);

var updateCheckedTodoItem = function (todoItem) {

// This code takes a freshly completed TodoItem and updates the database. When the MobileService

// responds, the item is removed from the list

todoTable.update(todoItem).done(function (item) {

todoItems.splice(todoItems.indexOf(item), 1);

});

};

更新记录时,需要在要更新的记录中包含主键。在本例中,id 字段是主键。当创建新的 Azure 移动服务时,会自动创建 id 列并使其成为主键。该字段是自动递增列。

记录的删除可以通过调用MobileServiceTable类的del()方法来执行。例如,下面的示例演示了如何从 todo 表中删除记录:

var deleteItem = { id:1};

todoTable.del(deleteItem);

update方法类似,del方法也需要传递对象的主键。

13.5 分页数据检索

问题

你需要控制从 Microsoft Azure 移动服务返回到你的通用 Windows 应用的数据量。

解决办法

在客户端使用takeskip查询方法从移动服务获取具体的记录数。

它是如何工作的

让我们用之前的食谱作为这个食谱的起点。

Add six more todo items from the app by changing the text and clicking the Save button.   Open the default.js file and replace the refreshTodoItems method with the following code. var refreshTodoItems = function () {     // Define a filtered query that returns the top 2 items.     todoTable.where({ complete: false })         .take(2)         .read()         .done(function (results) {             todoItems = new WinJS.Binding.List(results);             listItems.winControl.itemDataSource = todoItems.dataSource;         }); }; This example returns the top two items on the todo table, which are not marked as complete.   Run the application in the Windows desktop using the Local Machine option. You should see the first three todo items from the service, as shown in Figure 13-12.

A978-1-4842-0719-2_13_Fig12_HTML.jpg

图 13-12。

Windows app displaying only two records with paging

如果您想跳过表中一定数量的项,然后返回之后的记录,该怎么办?您可以使用skip方法来实现这一点。

以下是跳过前四条记录并返回其后四条记录的代码片段。这类似于第 2 页,可以多显示四条记录。

var refreshTodoItems = function () {

todoTable.where({ complete: false })

.skip(4)

.take(4)

.read()

.done(function (results) {

todoItems = new WinJS.Binding.List(results);

listItems.winControl.itemDataSource = todoItems.dataSource;

});

};

Note

移动服务在一个响应中有最多 50 个项目的自动页面限制。skip / take方法可以帮助在一个响应中检索更多的记录(如果需要的话)。

13.6 对从移动服务返回的数据进行排序

问题

您需要对移动服务从通用 Windows 应用返回的数据进行排序。

解决办法

您可以在查询中使用orderByorderByDescending函数。

它是如何工作的

让我们用之前的食谱作为这个食谱的起点。您将更新refreshTodoItems方法来对记录进行排序。

Open the default.js file and replace the refreshTodoItems method with the following code to sort by text in descending order.

var refreshTodoItems = function () {

todoTable.where({ complete: false }).orderByDescending("text")

.read()

.done(function (results) {

todoItems = new WinJS.Binding.List(results);

listItems.winControl.itemDataSource = todoItems.dataSource;

});

};

当您使用本地机器选项在 Windows 桌面中运行应用时,您会注意到列表现在以降序排序,如图 13-13 所示。

A978-1-4842-0719-2_13_Fig13_HTML.jpg

图 13-13。

Windows app displaying sorted data from a mobile service

为了按升序对数据进行排序,可以使用orderBy方法来指定对记录进行排序的列。下面的示例演示了如何按照"text"列以升序对 todo 表进行排序。

todoTable.where({ complete: false }).orderBy("text")

.read()

13.7 在服务器脚本中执行验证

问题

您希望在 Microsoft Azure Mobile Services 的服务器端 JavaScript 中执行验证。

解决办法

您可以在服务器脚本(插入、更新、删除等)中定义验证。).这可以从 Visual Studio 2015 或移动服务仪表板进行修改。

它是如何工作的

让我们使用前面的菜谱示例来演示如何在 Azure 移动服务中执行验证,然后在 Windows 应用中显示一条消息。

假设您想要验证在插入新记录时提交的数据的长度。您必须注册一个脚本来验证少于六个字符的数据。如果文本长度小于或等于六个字符,则需要显示一条错误消息。

Open the Server Explorer window in Visual Studio and expand the mobile service table.   Double-click the insert.js file to start modifying it within Visual Studio. You can also right-click and select the Edit Script option to edit the file, as shown in Figure 13-14. Note that when you modify and save the file, the file is automatically updated in Microsoft Azure.

A978-1-4842-0719-2_13_Fig14_HTML.jpg

图 13-14。

Script files in Visual Studio 2015 for Mobile Services   Replace the insert.js file with the following code snippet. function insert(item, user, request) {     if (item.text.length <= 6) {         request.respond(statusCodes.BAD_REQUEST, 'Text length must be greater than 6 characters');     } else {         request.execute();     } }   Open the default.js file from the project and replace the insertTodoItem function with the following: var insertTodoItem = function (todoItem) {                 todoTable.insert(todoItem).done(function (item) {                     todoItems.push(item);                 }, function (error) {                     // Display the error message                     var msg = new Windows.UI.Popups.MessageDialog(                         error.request.responseText);                     msg.showAsync();                 });             };   Run the app in Windows desktop using the Local Machine option and try to add a todo item with less than six characters. Click the Save button. The app should display the message shown in Figure 13-15.

A978-1-4842-0719-2_13_Fig15_HTML.jpg

图 13-15。

Windows app displaying a validation message from a mobile service

或者,您可以从“脚本”选项卡修改脚本,这可以通过在 Azure 管理门户的“数据”选项卡中选择表格来找到。

十四、磁贴和通知

众所周知,在 Windows 8 中,微软引入了一种使用磁贴启动应用的新方式,磁贴是用户体验中标志性的一部分。对于 Windows 10,还有一些令人兴奋和与众不同的附加功能。本章概述了 Windows 10 中可用的磁贴和通知。您将探索如何创建不同类型的磁贴和通知。

14.1 创建默认图块

问题

您需要在应用中添加一个默认图块。

解决办法

使用package.appxmanifest为 UWP 应用平铺和显示提供信息。

它是如何工作的

在 Visual Studio 2015 中创建新的通用 Windows 应用项目。打开项目的package.appxmanifest。这将打开清单编辑器窗口,如图 14-1 所示。

A978-1-4842-0719-2_14_Fig1_HTML.jpg

图 14-1。

Application package.appmanifest

如果未选择应用选项卡,请选择它。如果需要,更改显示名称的值。显示名称是应用列表中列出的已安装/可用的应用名称,并显示在应用的标题中。

在应用清单中,单击“视觉资源”选项卡。在“磁贴和徽标”部分,更改为徽标提供的图像,并选择 Windows 清单中的徽标。更改或输入应用的新简称,该简称应为 13 个字符。否则,它将被截断。选择显示简短 mime 的适当平铺尺寸。您可以以 W3DC 格式输入您喜欢的背景颜色(例如#FFFFFF)或使用默认的背景颜色。

编译项目并运行应用,以测试应用创建的图块标题和图像徽标。

14.2 创建自适应图块

自适应磁贴是 Windows 10 的新增功能。对于自适应磁贴,有新的轻量级 XML 模板,允许开发人员根据自己的要求设计磁贴通知内容,以支持不同的设备和显示器。

问题

您希望为您的 UWP 应用创建自适应切片。

解决办法

与标准单幅图块一样,使用自适应单幅图块模板提供单幅图块的内容。对于创建自适应单幅图块,有自适应单幅图块模板,可用于创建不同类型的单幅图块。

通知可视化工具( https://www.microsoft.com/store/apps/9nblggh5xsl1 )帮助开发人员设计自适应图块。它提供即时的视觉预览。这有助于您快速设计自适应图块并进行测试。它提供了一种简单的方法来配置 tile 属性,如文本、字体、显示颜色、显示名称、背景图像、徽章值等等。

自适应模板适用于不同类型的通知和不同的外形规格。自适应磁贴外观取决于安装应用的设备和通知类型(磁贴或 toast)。

自适应平铺 XML 模式语法如下:

<tile>

<visual>

<binding template="TileMedium">

...

</binding>

<binding template="TileWide">

...

</binding>

<binding template="TileLarge">

...

</binding>

</visual>

</tile>

binding元素中是 key,在这里指定了每个图块大小的内容。在一个 XML 负载中,可以指定多个绑定。以下是可在bindingtemplate参数中指定的不同类型的图块尺寸:

  • TileSmall
  • TileMedium
  • TileWide
  • TileLarge(仅桌面)

它是如何工作的

自适应图块模板基于 XML。让我们使用通知可视化工具为自适应图块生成 XML。

在 Visual Studio 2015 中创建新的通用 Windows 应用项目。这将创建一个新的 Windows 应用项目。从 Visual Studio 解决方案资源管理器的项目中打开 default.html 页。在default.html的 body 标签中添加以下 HTML 标记。

<input type="button" value="Update Adaptive Tile" id="btnUpdateAdaptiveTile" />

这个 HTML 在default.html页面上添加了一个简单的 HTML 按钮,带有文本“Update Adaptive Tile”。

现在,右键单击解决方案资源管理器中的项目,并选择添加➤新 JavaScript 文件。为文件提供一个名称:LoadTileandNotifications.js。添加以下代码:

function GetControl() {

WinJS.UI.processAll().done(function () {

var adaptiveTilebutton = document.getElementById("btnUpdateAdaptiveTile");

adaptiveTilebutton.addEventListener("click", AddAdaptiveTiles, false);

}

document.addEventListener("DOMContentLoaded", GetControl);

在前面的代码中,您为btnUpdateAdaptiveTile HTML 按钮添加了一个事件处理程序AddAdaptiveTiles()。然后在加载default.html时添加了getControl方法。

重新打开default.html并添加对LoadTileandNotifications.js文件的引用。

<script src="/js/LoadTileandNotifications.js"></script>

现在,让我们使用下面的代码片段在LoadTileandNotifications.js文件中添加一个AddAdaptiveTiles()事件处理程序方法。

function AddAdaptiveTiles() {

var adaptivetileXml = "<tile><visual displayName=\"UWP recipes\" branding=\"name\">"

+ "<binding template=\"TileSmall\"><group><subgroup><text hint-style=\"subtitle\"> Windows 10 Apps receipes </text><text hint-style=\"subtitle\">Adaptive Tiles</text></subgroup></group></binding>"

+ "<binding template=\"TileMedium\"><group><subgroup><text hint-style=\"subtitle\"> Windows 10 Apps receipes </text><text hint-style=\"subtitle\">Adaptive Tiles</text></subgroup></group></binding>"

+ "<binding template=\"TileLarge\"><group><subgroup><text hint-style=\"subtitle\"> Windows 10 Apps receipes </text><text hint-style=\"subtitle\">Adaptive Tiles</text></subgroup></group></binding>"

+ "<binding template=\"TileWide\"><group><subgroup><text hint-style=\"subtitle\"> Windows 10 Apps recipes </text><text hint-style=\"subtitle\">Adaptive Tiles</text></subgroup></group></binding>"

+ "</visual></tile>";

var adaptivetileDom = Windows.Data.Xml.Dom.XmlDocument();

adaptivetileDom.loadXml(adaptivetileXml);

var notifications = Windows.UI.Notifications;

var tileNotification = new notifications.TileNotification(adaptivetileDom);

notifications.TileUpdateManager.createTileUpdaterForApplication().update(tileNotification);

}

在这个事件监听器函数中,您创建了一个 XmlDocument 对象adaptivetileDom,它用于加载adaptivetileXml. adaptiveXml包含adaptiveTile的 XML 有效负载,该负载包含以下自适应图块绑定:

  • TileSmall
  • TileMedium
  • TileLarge
  • TileWide

在前面的代码中,使用了Windows.UI.Notifications名称空间。

adaptivetileXml中,所有瓷砖都有以下显示名称:UWP 食谱。下一个参数是 branding,设置为Name。这将在图块底部显示名称值。

<group><subgroup>元素用于对显示在标题上的内容进行语义分组。在这种情况下,首先显示“Windows 10 Apps recipes”,然后在下一行显示“Recipes on Tiles”。两个文本元素被组合在一起。

TileLarge绑定中,我们也在 tile 中显示图像和文本内容。该图像与文本一起显示,但是您也可以将其设置为磁贴的背景。

hint-width属性用于指定当图块中存在多列时的列宽。

创建 XMLDocument 后,创建一个类型为Windows.UI.Notifications.TileNotification()tileNotification对象,并将adaptivetileXml XmlDocument 对象作为参数传递给TileNotification类。TileNotification对象用于定义图块和与图块相关的可视元素。

在此之后,使用TileUpdateManager类将通知发送到应用的图块,这将通过使用createTileUpdaterForApplication().update()方法更改更新程序绑定到的指定图块的内容。

在 Windows 10 设备上运行应用时,点击更新自适应磁贴按钮,动态更新磁贴,如图 14-2 所示。

A978-1-4842-0719-2_14_Fig2_HTML.jpg

图 14-2。

Windows 10 adaptive tile update using Windows.UI.Notifications.TileNotification()

14.3 创建包含可视内容的祝酒通知

问题

您希望创建一个交互式 toast 通知,与图像一起显示,以覆盖 toast 中的应用徽标和内嵌图像缩略图。

解决办法

Windows 10 UWP 提供了 toast 通知,它是使用类似于自适应磁贴的 XML 模板开发的。Toast 通知 XML 主要包含三个关键元素:视觉、动作和音频。ToastNotificationManager用于发送 toast 通知。使用ToastNotificationManager向应用发送新通知。

它是如何工作的

在上一节中,您使用 XML 模式创建了一个自适应图块。以类似的方式,您将创建一个交互式 toast 通知,通知用户在出版社目录中添加了一本新书。

使用相同的项目。在default.html<body>标签中添加以下 HTML 标记。

<input type="button" value="Display Toast" id="btnDisplayToast" />

<br />

这在default.html页面上创建了一个简单的显示 Toast HTML 按钮。

打开 LoadTileandNotifications.js,在现有的GetControl()方法中添加以下代码:

var toastNotificationbutton = document.getElementById("btnDisplayToast");

toastNotificationbutton.addEventListener("click", DisplayToastNotification, false);

在前面的代码中,您基本上获得了对btnDisplayToast按钮的引用,并将 click 事件处理程序与AddToastNotification()方法相关联。

使用以下代码片段添加一个新的AddToastNotification事件方法:

function AddToastNotification()

{

var toastXML = "<toast><visual>"

+ "<binding template=\"ToastGeneric\"><text>Apress Catalog</text><text>Apress is working on new Windows 10 Receipes guide</text>"

+ "<image placement=\"appLogoOverride\" src=\"/img/Alarm.png\" /><image placement=\"inline\" src=\"/img/Pattern-Blue-Dots-background.jpg\" /></binding>"

+ " </visual>"

+ "</toast>";

var toastNotificationDom = Windows.Data.Xml.Dom.XmlDocument();

toastNotificationDom.loadXml(toastXML);

var notifications = Windows.UI.Notifications;

// Get the toast notification manager for the current app.

var notificationManager = notifications.ToastNotificationManager;

// Create a toast notification from the XML, then create a ToastNotifier object

// to send the toast.

var toast = new notifications.ToastNotification(toastNotificationDom);

notificationManager.createToastNotifier().show(toast);

}

在前面的事件侦听器方法中,adaptivetileXml变量包含 toast 通知的 XML 有效负载,这类似于“自适应图块”,但是在<binding>元素中,模板值被设置为ToastGeneric

然后创建一个类型为ToastNotification的新的toast对象,并指定toastNotificationDom XmlDocument。之后,使用ToastNotificationManager类向应用的磁贴发送通知,该类发送指定 toast 的内容。

在默认页面的仿真程序中运行应用。点击显示 Toast 按钮测试输出,如图 14-3 所示。

A978-1-4842-0719-2_14_Fig3_HTML.jpg

图 14-3。

Toast notification from UWP app

您可以创建与您的应用关联的 toast 通知,并在应用运行时动态通知用户。在下一个菜谱中,您将学习如何向 toast 通知添加操作。

14.4 创建带有操作的 Toast 通知

问题

您希望创建一个交互式 toast 通知,为用户显示可能的操作。

解决办法

<Actions>元素添加到 toast 通知 XML。

它是如何工作的

在前面的配方中,您使用 XML 模式创建了一个自适应 toast 通知。以类似的方式,您将创建一个带有操作的交互式 toast 通知,该通知将向用户通知添加到出版社目录中的新书,并允许用户采取操作。

让我们使用与上一个配方相同的项目。打开 LoadTileandNotifications.js 文件。添加一个新方法,AddInteractiveToastNotification()

function AddInteractiveToastNotification()

{

var toastXML = "<toast><visual>"

+ "<binding template=\"ToastGeneric\"><text>Apress Catalog</text><text>Apress is working on new Windows 10 Receipes guide</text>"

+ "<image placement=\"appLogoOverride\" src=\"/img/Alarm.png\" /><image placement=\"inline\" src=\"/img/Pattern-Blue-Dots-background.jpg\" /></binding>"

+ " </visual>"

+ "<actions><action content=\"check\" arguments=\"check\" imageUri=\"/img/storelogo.png\" /><action content=\"cancel\" arguments=\"cancel\" /></actions>"

+ " <audio src=\"ms-winsoundevent:Notification.Reminder\"/>"

+ "</toast>";

var toastNotificationDom = Windows.Data.Xml.Dom.XmlDocument();

toastNotificationDom.loadXml(toastXML);

var notifications = Windows.UI.Notifications;

// Get the toast notification manager for the current app.

var notificationManager = notifications.ToastNotificationManager;

// Create a toast notification from the XML, then create a ToastNotifier object

// to send the toast.

var toast = new notifications.ToastNotification(toastNotificationDom);

notificationManager.createToastNotifier().show(toast);

}

AddInteractiveToastNotification()事件处理程序方法中,唯一的区别在于 XML 有效负载,您添加了额外的元素来允许用户采取行动。当 toast 通知发送到应用时,它还会播放通知声音。动作在<actions><action>元素下指定。

default.html中,为新按钮添加以下行,以显示交互式通知事件:

<p>

<input type="button" value="Display interactive Toast" id="btnDisplayinteractiveToast" />

<br />

</p>

这段代码增加了一个新的按钮,显示交互式吐司。为了将AddInteractiveToastNotification()方法与btnDisplayinteractiveToast按钮相关联,让我们在现有的GetControl()方法中添加以下代码行。

var toastinteractiveNotificationbutton = document.getElementById("btnDisplayinteractiveToast");

toastinteractiveNotificationbutton.addEventListener("click", AddInteractiveToastNotification, false);

前面的代码与前面的配方相同,其中您将一个按钮单击事件处理程序与一个方法相关联。在这种情况下,您将带有btnDisplayinteractiveToast id 的按钮关联到AddInteractiveToastNotification()方法。

编译项目并在模拟器中运行。加载default.html页面后,按下显示互动吐司按钮。按钮点击通知以两种不同的可能动作显示给用户。还会播放通知声音,如图 14-4 所示。

A978-1-4842-0719-2_14_Fig4_HTML.jpg

图 14-4。

Interactive toast notification from app

在这个菜谱中,您学习了如何通过 toast 通知与用户进行交互。您还了解了如何让用户根据 toast 通知采取行动。

14.5 创建预定的磁贴和 Toast 通知

问题

您希望创建一个交互式 toast 通知,并向用户显示提醒。

解决办法

在 tile 和 toast 通知 XML 中添加一个<Actions>元素。

它是如何工作的

在前面的配方中,您使用 XML 模式创建了一个自适应 toast 通知。以类似的方式,让我们创建一个交互式的 toast 通知,通知用户在出版社目录中添加了一本新书,并允许用户采取行动。

让我们使用与上一个配方相同的项目。打开 LoadTileandNotifications.js 文件,添加下面的AddScheduledTileNotification()方法。

function AddScheduledTileNotification() {

var adaptivetileXml = "<tile><visual displayName=\"Future recipes\" branding=\"name\">"

+ "<binding template=\"TileSmall\"><group><subgroup><text hint-style=\"subtitle\"> Updated Tiles </text><text hint-style=\"subtitle\">Adaptive Tiles</text></subgroup></group></binding>"

+ "<binding template=\"TileMedium\"><group><subgroup><text hint-style=\"subtitle\">  Updated Tiles </text><text hint-style=\"subtitle\">Adaptive Tiles</text></subgroup></group></binding>"

+ "<binding template=\"TileLarge\"><group><subgroup><text hint-style=\"subtitle\">  Updated Tiles </text><text hint-style=\"subtitle\">Adaptive Tiles</text></subgroup></group></binding>"

+ "<binding template=\"TileWide\"><group><subgroup><text hint-style=\"subtitle\">  Updated Tiles </text><text hint-style=\"subtitle\">Adaptive Tiles</text></subgroup></group></binding>"

+ "</visual></tile>";

var adaptivetileDom = Windows.Data.Xml.Dom.XmlDocument();

adaptivetileDom.loadXml(adaptivetileXml);

var currentTime = new Date();

//notification should appear in 3 seconds

var startTime = new Date(currentTime.getTime() + 3 * 1000);

var scheduledTile = new Windows.UI.Notifications.ScheduledTileNotification(adaptivetileDom, startTime);

//Give the scheduled tile notification an ID

scheduledTile.id = "Future_Tile";

var tileUpdater = Windows.UI.Notifications.TileUpdateManager.createTileUpdaterForApplication();

tileUpdater.addToSchedule(scheduledTile);

}

在这个方法中,我们在局部变量adaptivetileXml中为图块设置新的 XML。然后我们创建了一个 XMLDocument 类型的本地对象adaptivetileDom,在其中我们加载了adaptiveXml文本。

要向 tile 发送计划更新,我们首先需要设置计划时间,为此我们创建一个startTime局部变量,并将值设置为当前时间和 3 秒。为了发送磁贴的预定更新,创建一个类型为Windows.UI.Notifications.TileUpdateManager.createTileUpdaterForApplication()tileUpdater对象,然后调用addToSchedule方法在配置的时间发送更新。

若要执行上述方法,请添加一个 HTML 按钮并绑定一个事件处理程序来执行上述方法。打开 default.html 并添加以下 HTML 代码片段,以添加一个带有文本的 HTML 按钮,计划的自适应瓷砖。

<p>

<input type="button" value="Scheduled  Adaptive Tile" id="btnScheduledAdaptiveTile" />

<br />

</p>

接下来,打开 LoadTileandNotifications.js,用下面几行代码更新现有的LoadTileandNotifications()方法:

var ScheduledAdaptiveTilebutton = document.getElementById("btnScheduledAdaptiveTile");

ScheduledAdaptiveTilebutton.addEventListener("click", AddScheduledTileNotification, false);

这为btnScheduledAdaptiveTile按钮添加了一个新的onclick事件处理程序,并关联了当点击预定的自适应平铺按钮时要执行的AddScheduledTileNotification方法。

要测试这一点,编译并运行应用。加载default.html页面后,点击预定自适应平铺按钮。这将在 3 秒钟内向图块发送通知。您可以通过检查图块标题和文本进行验证,这些标题和文本会在预定时间发生变化。

在本食谱中,您在预定时间向 UWP 应用磁贴发送了更新。当发送基于内容变化的动态更新时,如天气应用、电子邮件应用、旅行计划应用等,计划更新非常有用。

14.6 在单幅图块上创建或更新徽章

问题

您想要在牌上添加徽章。

解决办法

使用 tile XML 有效负载中的<badge>元素来显示徽章。使用BadgeNotification创建徽章。

它是如何工作的

在现有的项目中,我们将添加一个额外的方法UpdateTileBadge,来展示如何在图块上创建徽章更新。打开 LoadTileandNotifications.js 并添加以下方法:

function UpdateTileBadge()

{

AddAdaptiveTiles();

var badgeXml = "<badge value=\"alarm\"/>";

var badgeDom = Windows.Data.Xml.Dom.XmlDocument();

badgeDom.loadXml(badgeXml);

var notifications = Windows.UI.Notifications;

var badgeNotification = new notifications.BadgeNotification(badgeDom);

notifications.BadgeUpdateManager.createBadgeUpdaterForApplication().update(badgeNotification);

}

在这个方法中,我们调用AdaptiveTiles()方法来显示自适应图块。

然后我们添加badgeXML,它包含徽章的 XML 有效负载,以便在磁贴上显示警报。在badgeXml中,我们将徽章的值设置为“报警”。

然后我们创建一个类型为Windows.UI.Notifications.BadgeNotificationbadgeNotifications对象,并传递徽章通知的 XML。

接下来,调用createBadgeUpdaterForApplication.update()方法来更新带有徽章通知的磁贴。

现在打开 default.html 并添加一个新按钮来测试用徽章更新磁贴的UpdateTileBadge()方法。

<p> <input type="button" value="Update Badge" id="btnUpdateBadge" />

<br />

</p>

接下来,打开 LoadTileandNotifications.js,用下面几行代码更新GetControl()方法:

var badgeUpdatebutton = document.getElementById("btnUpdateBadge");

badgeUpdatebutton.addEventListener("click", UpdateTileBadge, false);

这将添加一个新的 onclick 事件处理程序btnUpdateBadge按钮,并关联在单击 Update Badge 按钮时执行的UpdateTileBadge方法。

当您编译并运行该应用时,单击default.html页面上的更新徽章按钮。这将更新磁贴,应用磁贴将在右上角显示带有 Windows 报警图标的徽章,如图 14-5 所示。

A978-1-4842-0719-2_14_Fig5_HTML.jpg

图 14-5。

Badge notification on a Windows UWP adaptive tile

可以在 badge XML 中指定不同类型的窗口标志符号,例如警报、警告、可用、错误、暂停、新消息等。

Note

在 UWP 应用中,徽章显示在右下角。

在本章中,您了解了 UWP 应用磁贴和各种更新磁贴的方法,以及如何通过磁贴添加通知,如何动态更新自适应磁贴的内容。

十五、设备功能

本章概述了 Windows 10 应用中的设备功能。您还将了解如何在您的 UWP 应用中开发蓝牙、文本到语音、语音到文本和传感器功能。本章还概述了 Cortana 在应用中的集成。

15.1 如何在应用包清单中指定设备功能

问题

您需要指定 Windows 10 应用所需的不同设备的功能。

解决办法

使用应用包清单文件指定DeviceCapability元素和关联的子元素。

它是如何工作的

在 Visual Studio 2015 中打开您正在为 Windows 10 应用开发的项目。

从解决方案资源管理器中,找到Package.appmanifest文件。双击文件将其打开。单击功能选项卡。选择你的应用将使用的设备功能。这将在应用中添加功能列表(见图 15-1 )。

A978-1-4842-0719-2_15_Fig1_HTML.jpg

图 15-1。

Capabilities tab in app package.appmanifest file

您还可以在 XML 编辑器中打开 app package.appmanifest文件,并使用<Capabilities>元素下的<Capability>元素添加设备功能;例如:

<Capabilities>

<Capability Name="internetClient" />

<Capability Name="allJoyn" />

<Capability Name="codeGeneration" />

<Capability Name="internetClientServer" />

<uap:Capability Name="blockedChatMessages" />

<uap:Capability Name="chat" />

<uap:Capability Name="videosLibrary" />

<uap:Capability Name="phoneCall" />

<uap:Capability Name="removableStorage" />

<DeviceCapability Name="microphone" />

<DeviceCapability Name="webcam" />

</Capabilities>

在本例中,该应用启用了以下功能:聊天、视频库、电话和可移动数据存储,如 USB 驱动器、麦克风和网络摄像头。请注意,有一些功能,如网络摄像头,不能使用package.manifest可视界面指定。您必须使用代码文件来完成这项工作。

15.2 如何为 Windows 应用的蓝牙指定设备功能

问题

您需要在 Windows 10 应用中访问蓝牙设备。

解决办法

使用package.manifestDeviceCapability元素定义访问蓝牙设备的设备能力。这适用于蓝牙 Rfcomm 和 Gatt APIs。

它是如何工作的

Open your Windows Universal Windows app project in Visual Studio 2015.   From Solution Explorer, locate the Package.appmanifest file. Right-click and open the Package.appmanifest file in the XML editor.   Locate the <Capabilities> section. Add the following elements under <Capabilities>:

<DeviceCapability Name="bluetooth.rfcomm">

<Device Id="any">

<Function Type="name:obexObjectPush"/>

<Function Type="name:serialPort"/>

<Function Type="name:genericFileTransfer"/>

</ Device>

</DeviceCapability>

在前面的代码中,<DeviceCapability>元素具有Name属性,该属性被指定为用于访问蓝牙 RFCOMM 设备的“bluetooth.rfcomm”。<Device>元素被设置为"any",以允许访问与<function>元素中指定的功能类型相匹配的任何设备。

<DeviceCapability>也可以用于为蓝牙 GATT 设备指定设备功能,如下面的代码片段所示:

<DeviceCapability Name="bluetooth.genericAttributeProfile">

<Device Id="any">

<Function Type="name:battery"/>

<Function Type="name:bloodPressure"/>

<Function Type=”serviceId:aaaaaaa”/>

</ Device>

</DeviceCapability>

在前面的代码中,蓝牙 GATT“任何”设备的 DeviceCapabilities 支持所提到的具有指定服务名称和服务 id 的功能。

15.3 如何找到可用于 UWP 应用的设备

问题

您想要获取连接到系统的设备列表-外部连接或可用于 UWP 应用。

解决办法

使用Windows.Devices.Enumeration.DevicePicker类来枚举应用可发现的设备。

它是如何工作的

在 Microsoft Visual Studio 2015 中使用 Windows 通用(空白应用)模板创建一个新项目。

从 Visual Studio 解决方案资源管理器中的项目打开 default.html 页。添加以下 HTML 标记以显示按钮和标签:

<body class="win-type-body">

<div>

<h2 id="sampleHeader" class="win-type-subheader">Description:</h2>

<div id="scenarioDescription">

Recipe to demo DevicePicker to allows users of your app to pick a device

</div>

</div>

<div id="scenarioContent">

<button id="showDevicePickerButton" >Show Device Picker</button>

</div>

</body>

在解决方案资源管理器中右键单击js文件夹。添加一个DevicePicker.js JavaScript 文件。在default.html中添加对这个js文件的引用。

<script src="/js/DevicePicker.js"></script>

在 Visual Studio 中打开devicePicker.js并添加以下脚本:

(function () {

"use strict";

var DevEnum = Windows.Devices.Enumeration;

var devicePicker = null;

var page = WinJS.UI.Pages.define("../default.html", {

ready: function (element, options) {

// Hook up button event handlers

document.getElementById("showDevicePickerButton").addEventListener("click", showDevicePicker, false);

}

});

在前面的代码中,我们声明了一个类型为Windows.Devices.Enumeration的变量。这个对象稍后将被用来创建DevicePicker对象。

当加载 DOM 时,page变量用于将其余的js脚本绑定到默认页面。

ready()函数中,我们将事件处理程序showDevicePicker绑定到showDevicePickerButton按钮。

添加下面的showDevicePicker()方法,这将使设备可用:

function showDevicePicker() {

var buttonRect;

devicePicker = new DevEnum.DevicePicker();

buttonRect = document.getElementById("showDevicePickerButton").getBoundingClientRect();

var rect = { x: buttonRect.left, y: buttonRect.top, width: buttonRect.width, height: buttonRect.height };

// Show the picker

devicePicker.show(rect);

}

})();

在单击showDevicePickerButton按钮时调用的showDevicePicker()事件处理程序中,我们创建了一个Windows.Devices.Enumeration.DevicePicker对象和一个矩形对象来显示选择器 UI 输出。

编译这个项目,并使用移动仿真器运行它,以获得所有设备的列表,如图 15-2 所示。

A978-1-4842-0719-2_15_Fig2_HTML.jpg

图 15-2。

Get enumeration of all devices available to app on system

15.4 如何创建音频流并基于纯文本输出语音

问题

你需要在你的应用中添加一个语音功能,让它能够阅读文本。

解决办法

使用Windows.Media.SpeechSynthesis.SpeechSynthesizer()在你的 UWP 应用中开发基于文本的音频/语音输出。

它是如何工作的

微软已经提供了预定义的声音,可以用来合成单一语言的语音。

在 Microsoft Visual Studio 2015 中使用 Windows 通用(空白应用)模板创建一个新项目。在项目package.appmanifest文件中,单击 Capabilities 选项卡,并选中 Microphone 和 Internet 复选框。这允许应用使用音频源。

在 Visual Studio 解决方案资源管理器中打开项目的default.html页面。在default.html<body>标签中添加以下 HTML 标记。

<body class="win-type-body">

<div id="scenarioView">

<div>

<h2 id="sampleHeader" class="win-type-subheader">>Convert text to speech.</h2>

</div>

<div id="scenarioContent">

<button id="btnSpeak" class="win-button">Speak</button>

<select id="voicesSelect" class="win-dropdown"></select>

<textarea id="textToSynthesize" style="width: 100%" name="textToSynthesize" class="win-textarea"> Hello World! This is an example of Windows 10 Universal Windows App Recipes</textarea>

<p id="errorTextArea"></p>

</div>

</div>

<div id="contentWrapper">

<div id="contentHost"></div>

<div id="statusBox">

Status:

<div id="statusMessage"></div>

</div>

</div>

</body>

当在调试模式下在移动仿真器中启动应用时,显示图 15-3 所示的内容。

A978-1-4842-0719-2_15_Fig3_HTML.jpg

图 15-3。

Text to speech GUI with drop-down list to select the language

如您所见,添加了四个主要控件:

  • 一个扬声器按钮
  • 允许用户选择可用语言的下拉列表
  • 包含预定义文本的文本框。该应用会将这些文本转换成音频
  • 语音播放和停止时显示消息的状态标签

在解决方案资源管理器中右击该项目,并选择“添加➤新 JavaScript 文件”。提供文件的名称。在本例中,我们将文件命名为 SpeechSynthesise。js。在文件中添加以下代码:

var page = WinJS.UI.Pages.define("../default.html", {

ready: function (element, options) {

try {

synthesizer = new Windows.Media.SpeechSynthesis.SpeechSynthesizer();

audio = new Audio();

var btnSpeak = document.getElementById("btnSpeak");

var voicesSelect = document.getElementById("voicesSelect");

btnSpeak.addEventListener("click", speakFn, false);

voicesSelect.addEventListener("click", setVoiceFunction, false);

var rcns = Windows.ApplicationModel.Resources.Core;

context = new rcns.ResourceContext();

context.languages = new Array(synthesizer.voice.language);

listbox_GetVoices();

audio_SetUp();

} catch (exception) {

if (exception.number == -2147467263) {// E_NOTIMPL

// If media player components aren't installed (for example, when using an N SKU of windows)

// this error may occur when instantiating the Audio object.

statusMessage.innerText = "Media Player components are not available.";

statusBox.style.backgroundColor = "red";

btnSpeak.disabled = true;

textToSynthesize.disabled = true;

}

}

},

unload: function (element, options) {

if (audio != null) {

audio.onpause = null;

audio.pause();

}

}

});

声明以下变量:

var synthesizer;

var audio;

// localization resources

var context;

var resourceMap;

在加载应用的设备上为default.html页面加载 DOM 时,会执行ready(函数。在这个函数中,创建一个类型为Windows.Media.SpeechSynthesis.SpeechSynthesizer()的本地synthesizer对象,它提供对微软设备上已安装的语音合成引擎的功能访问,并控制语音合成引擎(voice)。

第二个对象是audio,用于播放音频。然后我们为 Speak 按钮和voicesSelect下拉 HTML 控件关联事件监听器。

我们还创建了一个类型为Windows.ApplicationModel.Resources.Core的本地rcns对象。此对象用于枚举设备中所有可用的资源。后来,它被用来获取已安装的声音,并使用下拉控件显示它们。

在前面的代码中,我们还声明了在其他方法中使用的局部变量,这些方法被称为单击 Speak 按钮和voicesSelect下拉列表。请注意,如果设备中缺少媒体播放器组件,并且无法播放音频,我们还会捕获一个异常。如果出现异常,我们捕获它并在 HTML div对象中显示 StatusMessage 错误消息。

添加以下方法:

function audio_SetUp() {

audio.onplay = function () { // executes when the voice begins playing

statusMessage.innerText = "Playing";

};

audio.onpause = function () { // executes when the user presses the stop button

statusMessage.innerText = " Audio Completed";

btnSpeak.innerText = "Speak";

};

audio.onended = function () { // executes when the voice finishes playing

statusMessage.innerText = "Completed";

btnSpeak.innerText = "Speak";

voicesSelect.disabled = false;

};

}

audio_SetUp() method Sets up the voice element's events so the app UI updates based on the current state of voice playback.

接下来,添加以下方法:

function speakFn() {

var btnSpeak = document.getElementById("btnSpeak");

if (btnSpeak.innerText == "Stop") {

voicesSelect.disabled = false;

audio.pause();

return;

}

// Changes the button label. You could also just disable the button if you don't want any user control.

voicesSelect.disabled = true;

btnSpeak.innerText = "Stop";

statusBox.style.backgroundColor = "green";

// Creates a stream from the text. This will be played using an audio element.

synthesizer.synthesizeTextToStreamAsync(textToSynthesize.value).done(

function (markersStream) {

// Set the source and start playing the synthesized audio stream.

var blob = MSApp.createBlobFromRandomAccessStream(markersStream.ContentType, markersStream);

audio.src = URL.createObjectURL(blob, { oneTimeOnly: true });

markersStream.seek(0);

audio.play();

},

function (error) {

errorMessage(error.message);

});

}

speakFn()是用户点击应用上的发言/停止按钮时调用的主要方法。synthesizer.synthesizeTextToStreamAsync()方法用于将文本框中的文本转换成 Blob 流。然后,它通过音频播放该流。

接下来,添加下面的方法,允许用户从资源中选择不同的音频语音选项。

function setVoiceFunction() {

/// <summary>

/// This is called when the user selects a voice from the drop down.

/// </summary>

if (voicesSelect.selectedIndex !== -1) {

var allVoices = Windows.Media.SpeechSynthesis.SpeechSynthesizer.allVoices;

// Use the selected index to find the voice.

var selectedVoice = allVoices[voicesSelect.selectedIndex];

synthesizer.voice = selectedVoice;

// change the language of the sample text.

context.languages = new Array(synthesizer.voice.language);

}

}

在这个方法中,我们使用了Windows.Media.SpeechSynthesis.SpeechSynthesizer.allVoices()来获取allVoices对象中所有已安装的语音合成引擎(voices)。

接下来,添加下面的方法来从设备安装的声音中创建项目。这些声音随后显示在voicesSelect下拉控件中。

function listbox_GetVoices() {

/// <summary>

/// This creates items out of the system installed voices. The voices are then displayed in a listbox.

/// This allows the user to change the voice of the synthesizer in your app based on their preference.

/// </summary>

// Get the list of all of the voices installed on this machine.

var allVoices = Windows.Media.SpeechSynthesis.SpeechSynthesizer.allVoices;

// Get the currently selected voice.

var defaultVoice = Windows.Media.SpeechSynthesis.SpeechSynthesizer.defaultVoice;

var voicesSelect = document.getElementById("voicesSelect");

for (var voiceIndex = 0; voiceIndex < allVoices.size; voiceIndex++) {

var currVoice = allVoices[voiceIndex];

var option = document.createElement("option");

option.text = currVoice.displayName + " (" + currVoice.language + ")";

voicesSelect.add(option, null);

// Check to see if we're looking at the current voice and set it as selected in the listbox.

if (currVoice.id === defaultVoice.id) {

voicesSelect.selectedIndex = voiceIndex;

}

}

}

最后,如果出现任何错误消息,有一个通用的errorMessage()方法来显示errorTextArea对象上的错误。

function errorMessage(text) {

/// <summary>

/// Sets the specified text area with the error message details.

/// </summary>

var errorTextArea = document.getElementById("errorTextArea");

errorTextArea.innerText = text;

}

一旦创建完SpeechSynthesise.js文件,确保在default.html文件中添加一个引用。

<script src="/js/SpeechSynthesise.js"></script>

当你在 Windows 10 移动模拟器中运行应用时,应用会打开default.html文件。按“朗读”按钮以当前默认的声音播放声音。更新Status div中的值,如图 15-4 所示。

A978-1-4842-0719-2_15_Fig4_HTML.jpg

图 15-4。

Text to speech app

在这个菜谱中,您学习了如何使用Windows SpeechSynthesizer()类将文本转换成音频。请注意,您还可以用 SSML 语言指定文本,并将其传递给一个对象Windows.Media.SpeechSynthesis.SpeechSynthesizer(),以将指定的文本转换成音频。

15.5 如何为语音识别指定识别约束

问题

你需要创建一个允许语音识别的应用。

解决办法

使用Windows.Media.SpeechRecognition.SpeechRecognizer对象创建一个语音识别器,并使用Windows.Media.SpeechRecognition.SpeechRecognitionListConstraint指定不同的语音识别约束。

UWP 应用中有三种可能的语音限制。

  • SpeechRecognitionTopicConstraint:基于预定义的语法,依赖互联网连接。
  • SpeechRecognitionListConstraint:基于预定义的单词和短语列表。
  • SpeechRecognitionGrammarFileConstraint:添加了一个语音识别语法规范(SRGS)文件,所有的约束都在这个 XML 文件中指定。

这个菜谱使用SpeechRecognitionListConstraint将语音转换成文本。

它是如何工作的

在 Microsoft Visual Studio 2015 中使用 Windows 通用(空白应用)模板创建一个新项目。在项目package.appmanifest文件中,单击 Capabilities 选项卡,并选中 Microphone 和 Internet 复选框。这允许应用使用音频源。

打开default.html文件,复制以下代码:

<body class="win-type-body">

<div id="scenarioView">

<div>

<h2 id="sampleHeader" class="win-type-subheader">Speech to Text</h2>

<div id="scenarioDescription">

<p>Speech recognition using a custom list-based grammar.</p>

</div>

</div>

<div id="scenarioContent">

<div>

<button id="btnSpeak" class="win-button">Speak</button>

</div>

<p id="errorTextArea"></p>

</div>

</div>

</body>

在解决方案资源管理器中右击该项目,并选择“添加➤新 JavaScript 文件”。提供文件的名称。在本例中,我们将其命名为 Speechrecognisation。js。

将以下代码添加到Speechrecognisation.js文件中:

(function () {

"use strict";

function GetControl() {

WinJS.UI.processAll().done(function () {

var btnSpeak = document.getElementById("btnSpeak");

btnSpeak.addEventListener("click", buttonSpeechRecognizerListConstraintClick, false);

var resultTextArea = document.getElementById(resultTextArea);

});

}

document.addEventListener("DOMContentLoaded", GetControl);

前面的代码向 btnSpeak 按钮添加了一个事件接收器。现在添加一个buttonSpeechRecognizerListConstraintClick函数,当用户单击用户首选项表单控件上的 Speak 按钮时触发该函数。

function buttonSpeechRecognizerListConstraintClick() {

// Create an instance of SpeechRecognizer.

var speechRecognizer =

new Windows.Media.SpeechRecognition.SpeechRecognizer();

// You could create this array dynamically.

var responses = ["Yes", "No", "Hello", "Hello World"];

// Add a web search grammar to the recognizer.

var listConstraint =

new Windows.Media.SpeechRecognition.SpeechRecognitionListConstraint(

responses,

"YesOrNo");

speechRecognizer.uiOptions.audiblePrompt = "Say what you want to search for…";

speechRecognizer.uiOptions.exampleText = "Ex. 'Yes', 'No', 'Hello'";

speechRecognizer.constraints.append(listConstraint);

var resultTextArea = document.getElementById(resultTextArea);

// Compile the default dictation grammar.

speechRecognizer.compileConstraintsAsync().done(

// Success function.

function (result) {

// Start recognition.

speechRecognizer.recognizeWithUIAsync().done(

// Success function.

function (speechRecognitionResult) {

// Do something with the recognition result.

speechRecognizer.close();

},

// Error function.

function (err) {

if (typeof errorTextArea !== "undefined") {

errorTextArea.innerText = "Speech recognition failed.";

}

speechRecognizer.close();

});

},

// Error function.

function (err) {

if (typeof errorTextArea !== "undefined") {

errorTextArea.innerText = err;

}

speechRecognizer.close();

});

}

})();

前面的代码声明了一个名为speechRecognizer的变量。它被分配给Windows.Media.SpeechRecognition.SpeechRecognizer()类,表示语音识别器对象的容器。下一行有一个responses静态数组变量,用来存储识别出的语音约束值。

然后在类型为Windows.Media.SpeechRecognition.SpeechRecognitionListConstraint()的对象实例中引用它,该实例加载在responses数组中指定的所有值。

以下是语音识别器的用户界面设置。将SpeechRecognitionListConstraint listcontraint传递给speechRecognizer对象。

然后我们调用speechRecognizer.compileConstraintsAsync()方法来异步编译由constraints属性指定的所有约束。该方法执行提供了类型为SpeechRecognitionCompilationResult的输出,该输出是使用speechRecognitionResult成功函数捕获的。我们还捕获错误并使用errorTextArea元素显示它们。

一旦你完成了Speechrecognisation.js文件,确保你在default.html中添加了一个引用。

<script src="js/Speechrecognisation.js"></script>

就是这样。语音识别基于预定义的约束,在应用中可用。它可用于捕捉用户输入。

当您在 Windows Mobile 模拟器中运行该应用时,它看起来如图 15-5 所示。点按“开始”并说出具体的单词,例如“是”、“否”或“你好”语音识别器将对其进行验证。

A978-1-4842-0719-2_15_Fig5_HTML.jpg

图 15-5。

Speech recognition based on a custom list of words

15.6 如何在前台使用 Cortana 语音命令启动您的应用

问题

你想让用户能够使用 Cortana 语音命令在前台启动你的应用。

解决办法

使用语音命令定义(VCD)文件来定义语音命令,其中包含激活应用的命令。安装执行 app 时,VCD 文件安装在 Cortana 中。

用户可以说出 VCD 文件中指定的命令来启动应用。Cortana 在 Windows 语音平台和云托管的微软语音识别服务的帮助下识别用户语音命令。这两个服务都试图识别语音,Cortana 接收文本,并使用onactivated事件启动应用和应用中的语音命令。

它是如何工作的

在 Microsoft Visual Studio 2015 中使用 Windows 通用(空白应用)模板创建一个新项目。

在项目中添加新的视频命令定义文件CortanaVoiceCommands.xml。将以下 XML 代码添加到文件中:

<?xml version="1.0" encoding="utf-8" ?>

<VoiceCommands xmlns="http://schemas.microsoft.com/voicecommands/1.2

<CommandSet xml:lang="en-gb" Name="CortanaVoiceCommandSet">

<AppName>Win10Recipes</AppName>

<Example> Show Win10 Recipes </Example>

<Command Name="showDevicesAvailableRecipes">

<Example>Show</Example>

<ListenFor RequireAppName="BeforeOrAfterPhrase">{command}</ListenFor>

<ListenFor RequireAppName="ExplicitlySpecified">Listening to command </ListenFor>

<Feedback> Recipes available in App </Feedback>

<Navigate/>

</Command>

<PhraseList Label="command">

<Item>Devices</Item>

<Item>Text to Speech</Item>

</PhraseList>

</CommandSet>

</VoiceCommands>

在这个视频命令定义文件中,有几个主要元素。元素定义了用于激活应用和执行命令的命令。元素还具有指定命令语言的属性xml:Lang。在这个例子中,我们使用的是英国英语。

<CommandPrefix>是我们应用的唯一名称。它被用作语音命令的前缀或后缀来激活应用。<Commmand>元素用于命令用户可以说什么。<ListenFor>元素指定了 Cortana 应该识别的文本。<Feedback>元素指定了 Cortana 在启动应用时所说的文本。<Navigate>元素表示语音命令是在前台启动应用。

如果要在后台通过语音命令启动 app,使用<VoiceCommandService>

创建 VCD 文件后,安装 VCD 文件指定的命令。为此,使用installCommandDefinitionsFromStorageFileAsync方法。

从解决方案资源管理器中打开 d efault.js。在这里,调用onactivated方法并添加以下代码:

//load vcd

var storageFile = Windows.Storage.StorageFile;

var wap = Windows.ApplicationModel.Package;

var voiceCommandManager = Windows.ApplicationModel.VoiceCommands.VoiceCommandDefinitionManager;

wap.current.installedLocation.getFileAsync("CortanaVoiceCommands.xml")

.then(function (file) {

voiceCommandManager.installCommandDefinitionsFromStorageFileAsync(file);

});

var activationKind = args.detail.kind;

var activatedEventArgs = args.detail.detail;

在前面的代码中,我们使用了Windows.ApplicationModel.Package.current.installedLocation.getFileAsync方法来获取对 VCD 文件的引用。调用了installCommandDefinitionsFromStorageFileAsync方法来安装文件中指定的命令。现在,我们必须指定应用如何响应与 VCD 文件匹配的语音命令。为此,首先检查IActivatedEventArgs.Kind是否为VoiceCommand。在default.js中的标准代码后替换以下代码,以检查激活参数类型:

if (args.detail.kind === activation.ActivationKind.launch) {

if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {

// TODO: This application has been newly launched. Initialize your application here.

} else {

// TODO: This application was suspended and then terminated.

// To create a smooth user experience, restore application state here so that it looks like the app never stopped running.

}

args.setPromise(WinJS.UI.processAll());

}

else if (activationKind == Windows.ApplicationModel.Activation.ActivationKind.voiceCommand)

{

var speechRecognitionResult = activatedEventArgs[0].Result;

// Get the name of the voice command and the text spoken

var voiceCommandName = speechRecognitionResult.RulePath[0];

switch(voiceCommandName)

{

case "showDevicesAvailableRecipes":

var textSpoken = speechRecognitionResult.semanticInterpretation.properties[0];

var url = "Devices.html";

nav.history.backStack.push({ location: "/Devices.html" })

break;

default:

break;

}

}

};

app.oncheckpoint = function (args) {

// TODO: This application is about to be suspended. Save any state that needs to persist across suspensions here.

// You might use the WinJS.Application.sessionState object, which is automatically saved and restored across suspension.

// If you need to complete an asynchronous operation before your application is suspended, call args.setPromise().

};

app.start();

前面的代码检查了指定激活类型的Windows.ApplicationModel.Activation.ActivationKind值。检查ActivationKind是否为voiceCommand或其他方式。如果应用是使用语音命令启动的,那么您需要在speechRecognitionResult变量中获取用户所说的文本;要获取字符串,请使用activatedEventArgs

activatedEventArgs有一个名为Result的属性,它提供了SpeechRecognitionResult

要获取用户所说的文本,使用speechRecognitionResult.RulePath[0]并将其存储在voiceCommandName局部变量中。

使用此文本(voiceCommandName),您可以决定显示哪个应用页面。为此,请切换大小写,并将 voicecommandName 值与 VCD 文件中指定的命令名相匹配。在CortanaVoiceCommands.xml中,你指定命令名showDevicesAvailableRecipes。如果匹配,在devices.html中向用户显示应用页面。这样,应用就与 Cortana 集成在一起了。当用户使用语音命令启动应用时,您可以进一步增强以启动应用页面。

Note

您不能使用 Visual Studio 移动模拟器来测试这个配方,因为 Cortana 需要一个 Microsoft 帐户注册和登录过程,这在移动模拟器上不工作。相反,你需要在设备上安装应用,然后运行 Cortana 来测试应用在前台的启动。

十六、附加工具

Windows SDK 和 Microsoft Visual Studio 2015 提供了额外的工具和功能,让开发人员可以轻松调试和测试他们的 Windows 应用。本章涵盖了其中的一些工具,如 JavaScript 控制台窗口、DOM Explorer、诊断工具、Windows 10 移动仿真器附加工具。当在各种场景中测试应用时,这些工具使开发人员的工作变得更加容易。

16.1 JavaScript 控制台窗口

问题

在调试通用 Windows 平台应用时,您希望查看 JavaScript 错误或编写调试消息。

解决办法

在调试通用 Windows 平台应用时,使用 Visual Studio 2015 中的 JavaScript 控制台窗口查看 JavaScript 错误或编写调试消息。

它是如何工作的

Microsoft Visual Studio 2015 提供了一个名为 JavaScript 控制台窗口的工具,允许开发人员执行以下操作:

  • 显示和修改变量值。
  • 运行可以在当前上下文中执行的 JavaScript 代码。
  • 查看 JavaScript 错误、异常和消息。
  • 将应用中的消息显示到控制台窗口。

当应用运行时,会显示 JavaScript 控制台窗口。或者,您可以从 Visual Studio 菜单调试➤ Windows ➤ JavaScript 控制台打开 JavaScript 控制台窗口,如图 16-1 所示。

A978-1-4842-0719-2_16_Fig1_HTML.jpg

图 16-1。

Access JavaScript Console from Visual Studio 2015

要测试此功能,请使用 JavaScript 模板从 Visual Studio 2015 创建一个新的通用 Windows 平台应用。

使用本地计算机选项生成解决方案并运行它。您应该会看到应用在桌面上运行。在应用仍在运行的情况下切换到 Visual Studio。注意 JavaScript 控制台列出了页面中所有可能的 JavaScript 错误,如图 16-2 所示。

A978-1-4842-0719-2_16_Fig2_HTML.jpg

图 16-2。

JavaScript Console window displaying list of warnings and errors

JavaScript 控制台提供了以下选项:

  • 查看错误消息
  • 查看警告消息
  • 查看消息
  • 清除控制台的选项

开发人员还可以编写调试消息,当应用在 Visual Studio 2015 的调试模式下运行时,可以显示这些消息。这是通过使用console.log方法实现的。

让我们从项目的js文件夹中打开 default.js 文件,并将下面的代码添加到文件的第一行,就在 use strict 选项的下面。

console.log("This is a custom log message");

当您运行应用并查看 JavaScript 控制台窗口时,您会看到其中的消息,如图 16-3 所示。

A978-1-4842-0719-2_16_Fig3_HTML.jpg

图 16-3。

JavaScript Console window displaying the log message

表 16-1 列出了一些在控制台窗口中操作消息的常用命令。

表 16-1。

JavaScript Console Window Commands

| 命令名称 | 描述 | | --- | --- | | `assert(expression, message)` | 如果表达式计算结果为 false,则发送消息。 | | `clear()` | 清除控制台窗口中的消息。 | | `debug(message)` | 向控制台窗口发送消息;它与 console.log 相同 | | `error(message)` | 向控制台窗口发送错误消息。消息文本为红色,包含一个错误符号。 | | `info(message)` | 向控制台窗口发送消息;该消息以信息符号开头。 | | `log(message)` | 向控制台窗口发送消息。 |

16.2 DOM Explorer

问题

您需要检查应用的 HTML 元素的属性,以及调试和修改 HTML 和 CSS 样式的元素属性。

解决办法

使用 Visual Studio 2015 中的 DOM Explorer 检查和修改 HTML 和 CSS 元素的值,以便进行调试。

它是如何工作的

Web 开发人员和 Internet Explorer 用户应该知道 DOM Explorer,它是一种流行的调试工具。Microsoft Edge 和 Internet Explorer 中的 F12 开发人员工具提供了此选项。

由于 UWP 应用支持使用 web 技术进行开发,所以 UWP 应用和使用 Visual Studio tools for Apache Cordova 创建的应用也支持 DOM Explorer。

开发者可以在 Windows 中使用 Visual Studio 菜单 Debug ➤ Windows ➤ DOM Explorer 访问 DOM Explorer,如图 16-4 所示。

A978-1-4842-0719-2_16_Fig4_HTML.jpg

图 16-4。

Access DOM Explorer from Visual Studio 2015

您可以在 Visual Studio 中使用 DOM Explorer 执行下列操作:

  • 检查现场直播
  • 选择元素
  • 调试 CSS 样式
  • 调试布局
  • 查看 DOM 事件侦听器
  • 调试 WebView 控件

打开用 JavaScript 开发的现有 UWP 应用,并在本地机器选项中运行它。

切换到 Visual Studio 并选择 DOM Explorer 选项卡。您可以在应用运行时使用 F12 快捷键,在 F12 开发者工具中显示 DOM Explorer,如图 16-5 所示。

A978-1-4842-0719-2_16_Fig5_HTML.jpg

图 16-5。

DOM Explorer

在 DOM Explorer 窗口中,选择 body 标签下的段落元素。双击文本以修改消息。你应该也能在你的 UWP 应用上看到文本更新。

DOM Explorer 中的 Styles 选项卡允许开发人员修改样式元素的值,并查看它在应用页面上的呈现方式。

计算选项卡显示所选 DOM 元素的每个属性的最终值(见图 16-6 )。

A978-1-4842-0719-2_16_Fig6_HTML.jpg

图 16-6。

Computed tab in DOM Explorer

布局选项卡显示元素的盒子模型,并显示应用的布局,考虑偏移和边距(见图 16-7 )。

A978-1-4842-0719-2_16_Fig7_HTML.jpg

图 16-7。

Layout tab in DOM Explorer

你也可以在调试的时候刷新你的应用。为此,请按照下列步骤操作。

A978-1-4842-0719-2_16_Fig8_HTML.jpg

图 16-8。

Refresh Windows app button in Visual Studio When the app is running in an emulator, open the default.html file in Visual Studio and modify the source code.   Click the Refresh Windows app button in the Debug toolbar or hit the F4 shortcut key (see Figure 16-8).

应用页面会重新加载模拟器上看到的新更改。

16.3 诊断工具

问题

您希望分析 Windows 应用的性能,以确定潜在的瓶颈。您想要分析 CPU 使用率、UI 响应性等等。

解决办法

使用 Visual Studio 2015 中的诊断工具来执行和分析各种因素,如 CPU 使用率、GPU 使用率、HTML UI 响应性、JavaScript 内存和网络。

它是如何工作的

Visual Studio 探查器或诊断工具可以帮助您找到 Windows 应用中的性能瓶颈。它们向您展示了应用中的代码大部分时间花在哪里。

您可以通过导航到调试菜单并选择启动诊断工具而不调试来启动 Visual Studio 2015 诊断工具,如图 16-9 所示。

A978-1-4842-0719-2_16_Fig9_HTML.jpg

图 16-9。

Launching Diagnostic Tools in Visual Studio 2015

Visual Studio 诊断工具(参见图 16-10 )为开发人员提供了以下选项来测试他们的应用:

A978-1-4842-0719-2_16_Fig10_HTML.jpg

图 16-10。

Diagnostic Tools with the different options

  • CPU 使用情况
  • GPU 使用情况
  • HTML 用户界面响应
  • JavaScript 内存
  • 网络

默认情况下,目标是当前项目。这可以通过单击更改目标按钮并从提供的列表中选择选项来更改为正在运行的应用或已安装的应用等。

您可以在“诊断”对话框的“可用工具”部分选择要评测的工具。

选择工具后,单击开始按钮。这会启动应用,Visual Studio 会自动启动诊断工具并收集数据进行分析。

工具完成数据采集后,显示结果,如图 16-11 所示。

A978-1-4842-0719-2_16_Fig11_HTML.jpg

图 16-11。

Results of the Diagnostic Tools in Visual Studio 2015

了解应用如何使用 CPU 是分析和识别应用中性能问题的良好起点。CPU 使用率工具显示 CPU 在何处花费时间执行 JavaScript 代码的信息。

在分析 CPU 使用率报告时,开发人员可以检查 CPU 使用率时间线图表,并选择时间线段来查看详细信息。CPU 利用率时间线图显示了设备所有处理器内核中应用的 CPU 活动。

UI 响应工具可以帮助开发人员识别以下问题:

  • UI 响应能力。如果 UI 线程被阻塞,应用可能会响应缓慢。出现这种情况的可能原因包括过多的同步 JavaScript 代码、同步 XHR 请求,甚至是处理器密集型 JavaScript 代码。
  • 资源导致的加载时间慢。

GPU 使用工具检查 DirectX 应用中的 GPU 使用情况。它让开发人员可以确定是 CPU 还是 GPU 导致了性能瓶颈。

JavaScript 内存工具调查 JavaScript 堆,以发现诸如内存泄漏等问题。

网络工具允许开发人员检查影响您的 Windows 应用的各种网络操作的信息,包括 HTTP 请求和响应头、有效负载、cookies 等。

16.4 Windows 10 移动模拟器:附加工具

问题

您希望在没有实际设备的情况下,通过模拟与 Windows 10 移动设备的真实交互来测试应用的功能。这些现实世界的交互包括测试位置感知功能、加速度计等等。

解决办法

使用 Windows 10 移动模拟器,它是通用 Windows 平台工具的一部分。它包括额外的工具,让开发人员测试现实世界与设备的互动。

它是如何工作的

附加工具是 Windows 10 移动模拟器的一部分。让我们打开在前面的配方中创建的应用,并通过选择一个 Windows Mobile 模拟器而不是本地机器来运行项目。这将在 Windows 10 移动模拟器中启动您的应用。要在仿真器中打开其他工具,请单击工具按钮(> >)如图 16-12 所示。

A978-1-4842-0719-2_16_Fig12_HTML.jpg

图 16-12。

Windows 10 Mobile emulator with Additional Tools feature

这将打开“附加工具”窗口,开发人员可以在其中访问定位、网络和加速度计等工具,以便在仿真器上进行测试(参见图 16-13 )。

A978-1-4842-0719-2_16_Fig13_HTML.jpg

图 16-13。

Additional Tools window in emulator

模拟鼠标输入

您可以单击模拟器工具栏上的鼠标输入按钮来启用鼠标输入。这确保了模拟器中的任何鼠标点击都将作为鼠标事件发送到模拟器的操作系统。如果您的应用与可以用作输入的鼠标配对,这是一个非常有用的功能。

近场通信(NFC)

如果你的应用使用近场通信(NFC),NFC 标签(见图 16-14 )可能是一个有用的工具,可以用来测试你的应用,如近距离、点击共享、卡片仿真等场景。

A978-1-4842-0719-2_16_Fig14_HTML.jpg

图 16-14。

NFC tab in Additional Tools

你可以通过使用一对仿真器来模拟两部手机一起敲击来测试你的应用。

NFC 工具支持以下模式:

  • 邻近模式
  • HCE(主机卡仿真)模式
  • 智能卡读卡器模式

测试此功能时,“NFC”选项卡显示以下内容:

  • 选择的模式
  • 与点击和未点击事件相关的日志
  • 通过当前连接发送和接收的所有消息的副本

请注意,当您第一次在 NFC 选项卡中单击点击按钮时,您将收到 Windows 防火墙提示。

您需要从 Visual Studio 启动两个不同分辨率的模拟器来模拟两部电话一起敲击。

选中启用对等设备发现复选框。对等设备下拉框显示 Microsoft 模拟器和运行模拟器驱动程序的 Windows 机器。

当两个模拟器都在运行时,请按照下列步骤操作:

Select the target emulator.   Select the Send to peer device option.   Click the Tap button, which simulates the two devices tapping together.   Click the Untap button to disconnect the devices. To simulate reading messages from a device, follow these steps:   Select the Send to self radio option to test scenarios that require only one NFC-enabled device.   Click the Tap button to simulate tapping a device to a tag. You should hear the notification sound.   Click the Untap button to disconnect.

多点触摸输入

您可以使用 Windows 10 模拟器工具栏上的多点触摸输入按钮来模拟多点触摸输入,以进行挤压、缩放和旋转。

要模拟多点触控功能,请按照以下步骤操作:

Click the Multi-touch Input button on the emulator toolbar to enable this feature.   Two points appear on the emulator screen. Right-click and drag one of the touch points to position it. Left-click and drag the other touch point to simulate pinching, zooming, and rotating, and so forth.   You can click the Single Point Input button on the emulator toolbar to restore the normal input.

加速计

加速度计工具允许开发人员测试跟踪手机移动的 Windows 应用(见图 16-15 )。它模拟模拟器中的行为。

A978-1-4842-0719-2_16_Fig15_HTML.jpg

图 16-15。

Accelerometer tool in Additional Tools

加速度计传感器可以用实时输入或预先录制的输入进行测试。它可以用记录的数据模拟手机的震动。

Select the desired orientation from the orientation drop-down list.   In the middle of the accelerometer, you see a colored dot. Drag it to simulate the movement of the device in a 3D plane.

位置

您可以使用位置选项卡测试使用导航和地理围栏的应用。

您可以模拟以不同的速度和精确度从一个位置移动到另一个位置。定位工具(见图 16-16 )目前支持三种模式:

A978-1-4842-0719-2_16_Fig16_HTML.jpg

图 16-16。

Location tab in Additional Tools

  • 图钉模式:在地图上放置图钉。然后,您可以单击 Play all points,模拟器以指定的时间间隔按顺序将每个引脚的位置发送到模拟器。
  • 实时模式:当您在地图上放置图钉时,模拟器会在您放置图钉时将图钉的位置发送给模拟器。
  • 路线模式:在地图上放置图钉来指示路点。模拟器计算路线。

用户还可以在位置选项卡中执行以下操作:

  • 使用搜索框搜索位置。
  • 放大和缩小地图。
  • 将当前的一组图钉点保存到 XML 文件中,以便以后重新加载。
  • 明确所有要点。
  • 保存布线,并在下次处于“固定”和“布线”模式时加载它。

网络

“网络”标签允许开发者在不同的网络速度和信号强度下测试应用。

你可以在 2G、3G 和 4G 等各种网络速度下,以及在良好、一般和较差等不同信号强度下测试你的应用。

当您的应用调用 web 服务或传输数据时,此功能尤其有用。

十七、侧装和 Windows 应用认证套件

开发应用后,在将应用上传到商店之前,在各种机器上部署和测试应用是非常重要的。本章介绍了一些关于如何从命令提示符生成应用包的方法,并将您的应用加载到计算机上,然后使用 Windows 应用认证工具包来测试应用是否足以发布到 Windows 应用商店。第十八章包括一个从 Visual Studio 交互生成应用包的方法,因此,这不在本章讨论。

17.1 侧装你的应用

问题

您需要在 Windows 设备上下载您的应用,而无需提交到 Windows 应用商店,以便测试人员可以使用您创建的应用包文件安装和测试它。

解决办法

使用 PowerShell 运行Add-AppDevPackage文件(它是在生成包文件时创建的),以便将您的应用下载到 Windows 设备上。

它是如何工作的

你的应用的用户不能像安装传统桌面应用那样简单地安装通用 Windows 应用。

通用 Windows 应用只能从商店下载,然后安装在设备上。如果您不想去商店就想安装某个应用,您可以将该应用下载到设备上,以便用户可以安装和测试它。

您可以按照以下步骤将应用包下载到 Windows 10 设备。

Enable your device for sideloading.   Install your app using PowerShell.

侧面加载应用的第一步是确保在您的设备上启用侧面加载。您可以通过启动设置应用并访问更新与安全在您的 Windows 计算机上启用它。选择“开发人员”按钮,该按钮显示使用开发人员功能的各种选项。选择开发者模式以启用设备的侧面装载(参见图 17-1 )。

A978-1-4842-0719-2_17_Fig1_HTML.jpg

图 17-1。

Enable Sideload apps and Developer mode in Windows 10

一旦你选择了开发者模式,就会显示一个确认对话框(见图 17-2 )来确认你想要打开应用侧装。Sideload apps 选项允许您安装一个.appx文件和证书,该文件和证书是使用随软件包一起创建的 PowerShell 脚本运行应用所需的。此选项比开发人员模式更安全,因为您无法安装不受信任的应用。但是对于这个配方,让我们选择开发者模式并继续。

A978-1-4842-0719-2_17_Fig2_HTML.jpg

图 17-2。

Confirmation dialog for enabling sideloading

下一步是在机器上安装应用。要做到这一点,请遵循以下步骤。

Generate the package file for installation. This is covered in Chapter 18.   Copy the complete folder of the package file that you want to install onto the target machine. For example, if you have created the app bundle, the folder name will contain the version number and _test. If the version number is 1.0.0.0 and the project name is Recipe17.1, targeting AnyCPU, the folder would be Recipe17.1_1.0.0.0_AnyCPU_Debug_Test.   On the target machine that you want to sideload the app, open the folder. Right-click the Add-AppDevPackage.ps1 file and click the Run with PowerShell button on the context menu, as shown in Figure 17-3.

A978-1-4842-0719-2_17_Fig3_HTML.jpg

图 17-3。

The Run with PowerShell menu in Windows Explorer   Follow the information shown in the PowerShell command. When the package is successfully installed, you will notice the Your app was successfully installed message in the command prompt, as shown in Figure 17-4.

A978-1-4842-0719-2_17_Fig4_HTML.jpg

图 17-4。

App installation message in PowerShell command

现在,单击 Windows 中的开始按钮。找到应用并启动它。

17.2 分别安装证书和软件包

问题

您需要在 Windows 中分别安装软件包和证书。

解决办法

使用 PowerShell 运行Add-AppDevPackage文件(它是在生成包文件时创建的),以便将您的应用下载到 Windows 设备上。

它是如何工作的

Recipe 17.1 演示了使用 PowerShell 安装一个应用和证书。有些情况下,您可能希望分别安装证书和软件包文件。您可以先安装证书,然后使用Add-AppDevPackage PowerShell 命令。

如果要在 Windows 桌面上单独安装证书和软件包文件,需要执行以下步骤。

Open the folder where the app package was created. Ideally, this folder contains the following:

  • Add-AppDevPackage.resources 文件夹
  • add-appdevpackage . resources PowerShell 脚本文件
  • 项目名称 _ 版本 _ 平台. appx 文件
  • project name _ Version _ platform . cer 安全或证书文件

Double-click the certificate file (.cer) and then click the Install Certificate button on the Certificate screen (see Figure 17-5).

A978-1-4842-0719-2_17_Fig5_HTML.jpg

图 17-5。

Install Certificate screen   On the Certificate Import Wizard screen, select the Local Machine option under the Store Location group, as shown in Figure 17-6. Click Next.

A978-1-4842-0719-2_17_Fig6_HTML.jpg

图 17-6。

Select store location from the Certificate Import Wizard   In the UAC dialog, click the OK button to continue.   In the next certificate import screen, select the Place all certificates in the following store radio button and click the Browse button (see Figure 17-7).

A978-1-4842-0719-2_17_Fig7_HTML.jpg

图 17-7。

Select the certificate store to place the certificate   In the Select Certificate Store pop-up screen, select Trusted people and click the OK button (see Figure 17-8).

A978-1-4842-0719-2_17_Fig8_HTML.jpg

图 17-8。

Select Certificate Store screen   Click Next in the Certificate Import Wizard and then complete the certificate by clicking Finish (see Figure 17-9).

A978-1-4842-0719-2_17_Fig9_HTML.jpg

图 17-9。

Completion of the certificate import process   This installs the certificate to the Windows certificate store on the local machine. The next step is to install the app alone using the add-appxpackage cmdlet for PowerShell, as explained in the following steps.   Navigate to the AppPackages folder and identify the complete path of the package file (.appx) file that you want to install.   As shown in Figure 17-10, open Windows PowerShell from the Start menu and run the Add-appxpackage command by specifying the following parameters. Add-appxpackage –Path <Path to appx file>

A978-1-4842-0719-2_17_Fig10_HTML.jpg

图 17-10。

Add-appxpackage command in PowerShell to install the app   Once you enter the command, press the Enter key. This installs the app on your Windows 10 machine.

现在,您可以从“开始”菜单启动应用。

17.3 使用 Windows 应用认证套件验证您的 Windows 应用

问题

您希望通过交互式使用 Windows 应用认证工具包来验证您的通用 Windows 平台应用。

解决办法

从 Windows“开始”菜单启动 Windows 应用认证工具包,并指定要验证和测试的应用。

它是如何工作的

在将应用提交给商店进行认证之前,最好在本地对其进行验证和测试。这为开发人员提供了更多的信息,以防软件包出现任何问题。

Windows 应用认证工具包是一个非常棒的工具,可以帮助开发人员在本地验证和测试您的应用。Windows 应用认证套件包含在 Windows 10 的 Windows 软件开发套件(SDK)中。

以下步骤使用 Windows 应用认证工具包验证和测试 Windows 应用。

From the Windows Start menu, search for Windows app cert kit and then click the Windows App Cert Kit desktop app (see Figure 17-11).

A978-1-4842-0719-2_17_Fig11_HTML.jpg

图 17-11。

Windows App Certification Kit in the Start menu   In the Windows App Certification Kit, select the validation category that you want to perform. For example, if you are validating a Windows app, select Validate Store App (see Figure 17-12).

A978-1-4842-0719-2_17_Fig12_HTML.jpg

图 17-12。

Selection of the type of app to perform validation   Once you select the Store App option, you are provided with options to either select an app that is already installed on the machine or choose the package file that you want to validate. You can enable the Browse for app you want to validate radio button and click the Browse button to select the package file (see Figure 17-13).

A978-1-4842-0719-2_17_Fig13_HTML.jpg

图 17-13。

Selection of the app to validate and test   Once you have selected the app or the package file, click Next to continue. The subsequent screens display the tests workflows that are applicable for the app that you are testing (see Figure 17-14). If a test is not applicable to your app type, it is grayed out.

A978-1-4842-0719-2_17_Fig14_HTML.jpg

图 17-14。

Types of tests applicable for the app   Click Next. The Windows App Certification Kit begins validating the app, as shown in Figure 17-15.

A978-1-4842-0719-2_17_Fig15_HTML.jpg

图 17-15。

Windows App Certification Kit validating the app   Once the validation is complete, you are prompted to save the report in the XML file format, which displays the results, as shown in Figure 17-16. The Windows App Certification Kit creates an HTML file along with an XML report and saves them in a specified folder.

A978-1-4842-0719-2_17_Fig16_HTML.jpg

图 17-16。

Test results from the Windows App Certification Kit

17.4 在远程 Windows 10 设备上验证应用包

问题

你需要在远程 Windows 10 机器上验证你的应用包,并测试它。

解决办法

在远程计算机上安装 Visual Studio 远程工具和 Windows 应用认证工具包,并使用远程计算机选项在远程计算机上验证包。

它是如何工作的

当从 Visual Studio 生成包文件时,您还可以选择在远程计算机上验证它。

要在远程计算机上验证包,请按照下列步骤操作。

Enable your Windows 10 remote device for development by enabling Developer mode in the Use developer features in the Settings app, as shown in Figure 17-17. Note that the validation on the remote ARM device for Windows 10 is currently not supported.

A978-1-4842-0719-2_17_Fig17_HTML.jpg

图 17-17。

Enabling Developer mode in the Settings app   Download and install the remote tools for Visual Studio on the remote machine. Go to http://www.microsoft.com/en-us/download/details.aspx?id=48155&NavToggle=True . The remote tools for Visual Studio are used to run the Windows App Certification Kit.   Download the Windows App Certification Kit from https://dev.windows.com/en-us/develop/app-certification-kit and install it on your remote machine.   Now, start creating a package from your Windows app. In the Package Creation Completed wizard, select the Remote machine option and click the ellipsis button (see Figure 17-18).

A978-1-4842-0719-2_17_Fig18_HTML.jpg

图 17-18。

Package creation and the Remote Machine option   Enter your subnet/Domain Name Server (DNS)/IP address. Select the appropriate mode in Authentication Mode menu of Windows credentials (see Figure 17-19).

A978-1-4842-0719-2_17_Fig19_HTML.jpg

图 17-19。

Remote Connection screen   Click the Select button and then the Launch Windows App Certification Kit button. If the remote tools are running on the remote machine, you are connected and the validation tests should begin.

十八、商店和货币化

到目前为止,您应该已经完成了针对 Windows 10 操作系统的通用 Windows 平台应用的开发。您需要构建您的应用,并将其上传到 Windows 应用商店,用户可以在那里搜索和下载应用。在本章中,您将了解在 Windows 应用商店中获得您的应用所需的东西,以及如何利用应用内广告赚钱。

18.1 创建一个 Windows 应用开发者帐户

问题

您需要构建您的应用并将其上传到 Windows 应用商店。但要做到这一点,您需要首先使用您的开发人员帐户登录 Windows 开发人员中心。在开始上传阶段之前,您需要知道如何创建开发人员帐户。

解决办法

在线创建一个开发者帐户。有两种方法可以开始这个过程。

通过 Windows 开发中心注册访问帐户

Windows 开发中心是 Windows 应用开发的一站式门户。该门户提供了您开始 Windows 10 应用开发所需的工具。有代码示例、如何开发 Windows 10 应用的教程,当然还有提交应用的条款。可以在 http://dev.windows.com 访问 Windows 开发中心。当您导航到此页面时,您会看到一个获取开发人员帐户链接。点按它并按照屏幕指示完成创建您自己的开发人员帐户。开发者帐户允许您将应用(适用于所有 Windows 设备)提交到 Windows 应用商店。它还允许您管理您的应用,并分析您的应用在商店中的表现。

您可以注册以下类别之一:

  • 个人:此帐户类型允许您以个人、学生或非法人团体的身份开发和销售应用。这种账户的费用是 19 美元。
  • 公司:这种帐户类型适用于拥有注册商业名称的公司,用于开发和销售应用。这种账户的费用是 99 美元。

您需要提供以下信息才能获得帐户:

  • 您的联系信息
  • 要显示的发布者名称
  • 支付方式(VISA/MasterCard/PayPal)

通过 Visual Studio 注册访问帐户

您也可以通过 Visual Studio 注册为开发人员。

在 Visual Studio 中,从项目菜单中选择 Store ➤ Open Developer Account(参见图 18-1 )。

A978-1-4842-0719-2_18_Fig1_HTML.jpg

图 18-1。

Open a developer account from Visual Studio

此操作会打开一个新的浏览器窗口,并将您直接带到帐户注册页面。你必须按照屏幕上的指示来完成帐户注册。

18.2 为 Windows 10 打包一个通用 Windows 平台应用

问题

您已经完成了应用的开发。您已经完成了 Windows 开发人员中心的帐户注册。现在,您想要打包您的应用,以便提交到商店。

解决办法

要销售或分发 Windows 应用,您需要创建一个应用包或 appxupload 包,这是一个技术术语。使用通用 Windows 平台(UWP),您可以生成一个包(.appxupload)。此包已上载到 Windows 应用商店。一旦应用进入商店,就可以在任何 Windows 10 设备上安装和运行,包括手机、平板电脑、个人电脑等。

它是如何工作的

打包 Windows 10 应用需要分两步完成。首先,用某些属性和设置配置包。然后,生成要上传到商店的包。

配置应用包

要创建应用包,您需要首先设置描述您的应用的某些属性和设置。应用属性和设置存储在一个名为应用清单文件的文件中,该文件位于项目的根目录下,名为package.appxmanifest。您在清单中设置的一些属性/设置是用于应用切片的图像或应用支持的方向。

应用清单文件是一个 XML 文件。Visual Studio 提供了一个基于 GUI 的清单设计器/编辑器来编辑该文件。使用 GUI 设计器/编辑器,很容易对应用清单进行更改。

以下步骤提供了如何配置软件包的说明:

A978-1-4842-0719-2_18_Fig2_HTML.jpg

图 18-2。

Application package manifest editing In Solution Explorer, expand your application’s project node.   Double-click the package.appxmanifest file. Visual Studio will launch the manifest designer/editor (see Figure 18-2).

清单文件有几个选项卡,用于配置应用的不同方面。

  • 应用:配置应用的显示名称、起始页、默认语言、描述、支持的方向、锁屏通知模式和磁贴更新信息。

  • Visual Assets: Configures your app’s visual assets, such as tile images and logos, the badge logo, and the splash screen (see Figure 18-3).

    A978-1-4842-0719-2_18_Fig3_HTML.jpg

    图 18-3。

    Visual Assets

  • Capabilities: Any capabilities that your app needs has to be declared in this area of the manifest file (see Figure 18-4).

    A978-1-4842-0719-2_18_Fig4_HTML.jpg

    图 18-4。

    Capabilities

  • Declarations: Use to add any declarations (for example, protocol or share target) for your app and sets their properties (see Figure 18-5).

    A978-1-4842-0719-2_18_Fig5_HTML.jpg

    图 18-5。

    Declarations

  • Content URIs: Specifies which pages in the app can be navigated to by a frame, and URIs that can be navigated to when loaded in a web view (see Figure 18-6).

    A978-1-4842-0719-2_18_Fig6_HTML.jpg

    图 18-6。

    Content URIs

  • Packaging: Sets the package details, such as package name (note: this is not the application name, rather just the package name), package display name, version details, publisher, publisher display name, and package family name (see Figure 18-7).

    A978-1-4842-0719-2_18_Fig7_HTML.jpg

    图 18-7。

    Packaging

创建应用包

在使用清单文件配置应用包之后,接下来要做的事情是生成或创建包。该包是一个 appxupload 文件。Visual Studio 提供了创建应用包向导,您接下来将使用该向导。按照以下步骤创建包:

In Solution Explorer, open the solution of your Universal Windows app project.   With the project opened in the Solution Explorer, right-click your project. Choose Store ➤ Create App Packages from the context menu (see Figure 18-8).

A978-1-4842-0719-2_18_Fig8_HTML.jpg

图 18-8。

Create App Packages   The wizard will be invoked. In the Create Your Packages dialog, select Yes to build packages and upload to the Windows Store (see Figure 18-9).

A978-1-4842-0719-2_18_Fig9_HTML.jpg

图 18-9。

Create App Package wizard If you chose No, Visual Studio would not create the required .appxupload file required for Store submission. This option should be used when you only want to sideload your app to run it on an internal device.   Next, you need to sign in to your Windows Dev Center account (see Figure 18-10).

A978-1-4842-0719-2_18_Fig10_HTML.jpg

图 18-10。

Create App Package Dev Center Sign in   Next, you need to select a name for your package, or you can reserve a name for your package from the wizard. The name you select needs to be unique to the Windows Store (see Figure 18-11).

A978-1-4842-0719-2_18_Fig11_HTML.jpg

图 18-11。

Selecting app name   Next, you need to select and configure the package information: the output location where the package will be saved, and the version and the architecture configuration for the build. Make sure to select all three architecture options (see Figure 18-12).

A978-1-4842-0719-2_18_Fig12_HTML.jpg

图 18-12。

Configuring package details   Click Create to generate the appxupload package, which is generated at the selected output location. You can then submit the appxupload package to the Store. Next, you see Package Creation Completed dialog (see Figure 18-13).

A978-1-4842-0719-2_18_Fig13_HTML.jpg

图 18-13。

Creation Completion dialog It is important that you validate your app before submitting it to store for certification. Validation can be done by using the Windows App Certification Kit (WACK) that is installed as part of the SDK on your machine. Validation can be done on your local machine or on a remote machine.   To validate locally, select the Local machine radio button in the Package Creation Completed dialog. Click the Launch Windows App Certification Kit button. The Windows App Certification Kit performs tests and shows you the results.   If your app has passed the tests, you are ready to submit your app to the Store.

18.3 向 Windows 应用商店提交应用

问题

您已经完成了包的创建。已为您的应用生成了一个 appxupload 包。您现在需要将应用提交到商店进行认证。

解决办法

为您的应用创建 appxupload 包后,下一步是将其提交到商店进行认证。认证后,您的应用会列在 Windows 应用商店中,以便用户可以搜索和下载安装。您可以使用 Windows 开发人员中心仪表板将应用包提交到 Windows 应用商店。下面概述了提交的过程。

Log in to the Windows Dev Center using your dev center account credentials. Head over to http://dev.windows.com and sign in.   Click the Dashboard link.   On the dashboard page, you see the My Apps section on the left-hand side of the page. Under this section, the app name you reserved during package creation is listed with an In progress status. Click the app name (see Figure 18-14).

A978-1-4842-0719-2_18_Fig14_HTML.jpg

图 18-14。

Apps listing in Windows Dev Center dashboard   Next, you are presented with the App Overview page. Here you need to click the Start your submission button in the Submissions section.   Next, you are presented with the submission screen. Here you need to provide information related to pricing, the application properties, the application package, which countries you want your app to be available in, and any other instructions for certification team. Pricing and availability: Here you provide the pricing for your app or decide to list it as free. You also have option to choose the countries in which you want to list your app.   App Properties: Here you provide information such as the category and subcategories to which your app belongs in, as well as the age rating, any hardware preferences, and app declarations.   Packages: Here you submit the appxupload package that was generated by Visual Studio.     Once you have followed all the steps in the submission process, you can click the Submit to the Store button. Your package will then undergo a workflow. Your app is signed with a certificate, and then the certification team performs certification tests. Once certified by the certification team, your app is published to the Windows Store.

18.4 在您的 UWP 应用中使用 Windows 广告中介

问题

你已经开发了你的 Windows 10 应用,并且你正在考虑通过运行广告来赚钱。你想与多个广告提供商签约,以便在你的应用中显示他们的广告。你的应用需要一个广告中介控件。

解决办法

应用内广告是你从应用中赚钱的方式之一。你可以订阅广告提供商,并在你的应用中运行他们的广告。你的应用中显示的广告的印象会得到报酬。不同的提供商有不同的与广告印象相关的经济学。但是要显示广告,你需要先安装 Windows Ad Mediator,这个控件可以帮助你显示来自多个提供商的广告。让我们学习如何从 Visual Studio 安装一个 Ad Mediator 控件。

Open your project in Solution Explorer. Expand your project if it is not expanded already.   From the menu bar, select Tools➤ Extensions and Updates (see Figure 18-15).

A978-1-4842-0719-2_18_Fig15_HTML.jpg

图 18-15。

Extension and Updates dialog   Select Online from the left tree. Type Windows Ad Mediation in the dialog search bar (see Figure 18-16).

A978-1-4842-0719-2_18_Fig16_HTML.jpg

图 18-16。

Windows ad mediation   Click Download on the Windows ad mediation package shown in the search results. This launches a browser and downloads the executable. After it downloads, install the MSI and follow the onscreen instructions. Restart Visual Studio once installation has finished.

现在,您可以在应用中使用 Windows Ad 中介控件了。

18.5 在应用中显示广告

问题

您已经安装了 Windows Ad Mediation SDK,现在您希望开始在您的应用中显示广告。你想在你的应用页面上放广告。

解决办法

为了在应用页面中显示广告,您需要添加对 Windows 广告 SDK 的引用,该 SDK 是作为 Windows 广告中介安装的一部分安装的。一旦将引用添加到 Windows Ad SDK 中,您就可以在任何页面上实例化中介控件,并在其中显示广告。以下步骤解释了如何添加中介控件。

Open your project in Solution Explorer. Expand your project if it is not expanded already.   Right-click the References node and select Add Reference from the context menu.   In the Reference Manager dialog, select Microsoft Advertising SDK for JavaScript and click OK (see Figure 18-17).

A978-1-4842-0719-2_18_Fig17_HTML.jpg

图 18-17。

Reference Manager dialog   Open the default.html or any other file where you want to place the ads.   In the <head> section, after the project’s JavaScript references of default.css and default.js, add the reference to ad.js. <!-- Microsoft Advertising required references --> <script src="/Microsoft.Advertising.JavaScript/ad.js" ></script>   Modify the <body> section in the default.html file (or other HTML files, as appropriate for your project) to include the following: <div id="myAd" style="position: absolute; top: 50px; left: 0px; width: 300px; height: 250px; z-index: 1"       data-win-control="MicrosoftNSJS.Advertising.AdControl"       data-win-options="{applicationId: 'd25517cb-12d4-4699-8bdc-52040c712cab', adUnitId: '10043121'}">     </div>   Compile and run the app to see it with an ad (see Figure 18-18).

A978-1-4842-0719-2_18_Fig18_HTML.jpg

图 18-18。

Universal Windows app with ads   Note

在前面的代码片段中提供的应用 id 和 ad 单元 id 是 Microsoft 在开发过程中为您提供的测试值。出于测试目的,应用 id 将是相同的,但是有不同的测试广告单元,可以用于测试不同的广告维度。位于 https://msdn.microsoft.com/en-US/library/mt313178(v=msads.30).aspx 的微软文档页面提供了关于测试广告单元 id 的更多信息。

To generate ApplicationID and AdUnitId in your production apps, follow these steps: Start the store submission process in the Windows Dev Center.   Make sure that you set the App Category in the App Properties section.   Next, select Monetization ➤ Monetize with ads from the options in the section on the left of the page.   On the Monetize with ads page, under the Microsoft Advertising ad units section, click Show Options.   Enter a name for your ad unit. Select the Ad unit type and the device family where the ad will be shown. Click the Create ad unit button.   Now you have created an ad unit. Copy the application id and ad unit id and paste into the ad control in your app.   Regenerate the package and use the new package in your submission process.

posted @   绝不原创的飞龙  阅读(8)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示