Windows10 开发秘籍(三)

原文:Windows 10 Development Recipes

协议:CC BY-NC-SA 4.0

十一、后台任务

在任何应用中,您可能必须在后台静默执行某些任务。通用 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.

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11-1。

New Project dialog   Visual Studio prepares the project, which will look like what’s shown in Figure 11-2 once done.

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 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.

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 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.

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 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).

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 12-4。

Current location in a Windows desktop family app

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 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).

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 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.

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 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.

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 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.

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 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 找到。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 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 )。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 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参数也是为了显示交通信息。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 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 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 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.

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 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.

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 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.

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 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.

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 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.

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 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.

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 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.

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 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.

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 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 移动服务中创建数据库表。

它是如何工作的

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 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 所示。单击提交按钮。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 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).

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 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.

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 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.

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 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.

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 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 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 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.

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 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.

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 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 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 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 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 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 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 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 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 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 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 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 )。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 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 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 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 所示的内容。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 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 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 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 所示。点按“开始”并说出具体的单词,例如“是”、“否”或“你好”语音识别器将对其进行验证。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 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 来测试应用在前台的启动。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值