编者寄语 – 从 3.0 开始的发展之路
最后更新于:2022-04-01 06:55:56
* * *
WINDOWS 10 2015 年特别版
此文章由机器翻译。
# 编者寄语 - 从 3.0 开始的发展之路
通过 [Michael Desmond](https://msdn.microsoft.com/zh-cn/magazine/mt149362?author=Michael+Desmond) |Windows 2015 年
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-08_568f2a84ad00b.jpg)
四分之一世纪前 Microsoft 发布了其长时间的历史记录中的软件的最重要的部分。Windows 3.0 不是第一个版本的 Windows 中,也不是最好的但它是最重要方面其旗舰版的影响。一次的 PC 行业的领导层时的氛围,Windows 3.0 未超过巩固空间中的 Microsoft 的习惯用手。它设置为 PC 平台的演变过程 — 通过扩展,软件开发和 IT — 两个数十年时间来形成。
Windows 3.0 进入了市场之前,PC 平台可能已在一个完全不同的方向。Windows 2.0 就是只是另一个图形化的操作环境和产品 (如 GEM 和 DESQview boasted 创新的用户界面和多任务处理功能。IBM,同时,必须说服 Microsoft,以帮助其作为 DOS 的后继操作系统开发 OS/2。
所有这些更改时的 Microsoft 工程师对 — David Weisse 和 Murray Sargent — 花费 1988 安静地黑客 Windows 2.x 内核、 DLL 库和其他资产以获取上 286 在保护模式下运行的 Windows 中的月份 PC。(您可以阅读在 Sargent 的奇妙 retelling [bit.ly/1O6glhy](http://bit.ly/1O6glhy)。) 从 640 KB 内存屏障中解脱出来和启用的一些支持的驱动程序和图形工作,Windows 突然变得不是很大得多的内容。Steve Ballmer 和比尔 · 盖茨,尽管通知的 skunkworks 工作能力,请立即进行识别。Windows 3.0 已批准为正式的项目,并在其 1990 年两年内版本将销售超过 1000 万个副本。
Windows 3.0 进行了很好很多事情。它建立 2012年中 Windows 8 的发布之前会忍受的 Microsoft 操作系统的外观和感觉。和其恢复为急剧增加的腦市場行,提示它来开发自己的图形化操作系统的 Microsoft 的方法。但是,从根本上讲,实践证明其出平台本身的适应性。
四分之一世纪前 Microsoft 是项强有力的年轻人 upstart 找到一种方法来注入到 faltering 的 Windows 特许经营的新的活力并引导人们的个人计算两个数十年来形成课程。该项成就回显今天听说过。Windows 10 是 Microsoft 的新外观操作系统的第三个迭代,代表重大的进步。从完善和连贯双模式用户界面到 Microsoft 的通用 Windows 平台 (UWP) 构想的令人印象深刻作用域,在许多方面的 Windows 10 执行 Windows 3.0 所实现的前 25 年。它扩展的平台,视野并为开发人员和最终用户等提供了一个非独占路径前滚。
现在,Windows 开发人员可以编写应用程序并让它运行任何现代的、 已启用 Windows 的客户端上,从最小的物联网设备的最大面中心基于房间的显示,并为每个电话、 平板电脑和 PC 之间。Windows 10 还对 Android 和 iOS 的桥移动应用程序开发人员并提供了以及完全支持传统的.NET 和基于 COM 的应用程序中通过虚拟化。
四分之一世纪前,我们在图形的年龄的垂直尤为。现在,我们输入无处不在的、 基于设备的计算和其上触摸和语音基于 Ui 的依赖性的时代,出现了问题: 现代的时代可能会 Windows 3.0 吗?
* * *
Michael Desmond *是 MSDN 杂志主编。*
结束语 – 欢迎使用 Windows 10 应用开发
最后更新于:2022-04-01 06:55:54
WINDOWS 10 2015 年特别版
此文章由机器翻译。
# 结束语 - 欢迎使用 Windows 10 应用开发
通过 [Kevin Gallo](https://msdn.microsoft.com/zh-cn/magazine/mt149362?author=Kevin+Gallo) |Windows 2015 年
我希望您获得愉快的 MSDN 杂志 》 将重点放在应用程序开发的通用 Windows 平台 (UWP) 此特殊版本。我 Kevin Gallo,在 Windows 开发人员平台团队的副总裁。我的团队负责创建 UWP,并为您提供很好的 UXes 并向我们提供反馈以帮助我们使其更好地在将来使用它非常期待。
有关创建一个平台像 UWP 获取若要查看一些令人称奇的人员的最佳和最令人满意的事情之一对它所执行的操作。您的应用程序和游戏将变为现实的平台并创建吸引、 合作并而使用户满意用户的体验。我们这里所说我们喜欢开发人员和他们是太好了创建和我们期待着看到什么意味着您将提出下一步。
使用 Windows 10 和 UWP,则可以为您可以为目标 — 与单个应用程序 — 宽的 Windows 设备。这可能是因为平台都有一套共享的 Api、 一组语言和框架、 一套工具和统一的 Windows 应用商店。
这意味着您的应用程序可以更大的访问群体。读者包括用户的 Windows 10 Pc — 这是将近 100 万成绩斐然 — 物联网 (IoT) 设备、 Windows Phone 手机 (人口中说出来更高版本中 2015年),以及该图面中心,Xbox 和 HoloLens (即将在 2016年) 平台。
与 UWP,很容易地使用我们自适应的控件来使外观精美跨各种设备类型、 输入方法和屏幕大小的应用程序。您还可以修改您的应用程序以创建针对特定设备,范围从最小的 IoT 传感器到最大的图面中心交互式白板的自定义的体验和显示。这意味着您可以使用一个 UWP 应用程序专门针对每个设备和使用情况的方案有最自然而感到舒适的用户的方式的体验与此不同目标受众为目标。
本期 MSDN 杂志 》 提供了简介以及许多 UWP,范围从多个屏幕的设计指南和优化应用程序在后台处理和多个任务,以及更多内容的改进的之间的通信的全新且激动人心的功能的实用指南。
对于那些已有 Windows 8.1 或 Windows Phone 8.1 上的应用程序的用户,我想强调 UWP 是只是您一直使用相同的现代平台的演变。您可以继续在您的语言和使用您选择的框架中编写针对 Windows 平台的应用程序,无论是 C/c + +、 C#、 Visual Basic、 JavaScript、 XAML 或 Silverlight。可以重复使用的最小的工作量现有代码的重要部分,然后将重点讲述您增强 Windows 10 的特有功能的应用程序体验的时间。
超出本期 MSDN 杂志 》,我们提供了我们认为将作为 UWP 应用程序开发人员对您有用的在线内容丰富。下面是只是几个您可能希望在签出的资源:
* 构建针对 Windows 的应用程序: 我们用每周添加的新内容的开发人员博客 ([bit.ly/1KZUio1](http://bit.ly/1KZUio1))
* 生成于 2015 年: 会议视频和会议中的幻灯片都是在第 9 频道网站上 ([bit.ly/1NHlnz7](http://bit.ly/1NHlnz7))
* Developer's Guide to Windows 10: 从与实际示例讲授的 Microsoft 虚拟学院 18 部分的视频系列 ([bit.ly/1LrDVmM](http://bit.ly/1LrDVmM))
* Windows 开发人员中心: 可下载的工具、 设计指南、 操作方法指南以及完整的 API 参考文档
* 开发人员中心 ([dev.windows.com](https://dev.windows.com/))
* 工具下载 ([bit.ly/1MVjblj](http://bit.ly/1MVjblj))
* 将设计文档移交 ([bit.ly/1LC6eej](http://bit.ly/1LC6eej))
* 操作方法指南 ([bit.ly/1WdJkkG](http://bit.ly/1WdJkkG))
* 代码和应用程序示例: 在 GitHub 存储库中可用 ([bit.ly/1RhG46l](http://bit.ly/1RhG46l))
您是否计划使用 UWP 和 Windows 10 吗? 如果是这样,我们期待收到您的反馈。我们依靠开发人员输入来帮助定位我们计划和优先级。使您通过提供反馈通过我们的 Windows 开发人员用户之声听到的声音。转到 [wpdev.uservoice.com](http://wpdev.uservoice.com/) 并留下我们一项建议,或对具有重要意义且与自己相关的现有建议投票。
我希望您发现此月刊的 MSDN 杂志 》 很有用。我不能坐等看您和 Windows 开发人员社区将生成与通用的 Windows 平台的最大优势 !
* * *
Kevin Gallo *是在 Microsoft 的 Windows 开发人员平台的公司副总裁,负责设计和传送通过其开发人员生成有意义的应用程序和服务为 Windows 系列设备的平台组件。Gallo 拥有学士的工程卡耐基-梅隆大学计算机工程学位。在业余时间他喜欢骑车旅行、 徒步旅行和与家人划船。*
游戏开发 – 使用 Unity 为通用 Windows 平台编写游戏
最后更新于:2022-04-01 06:55:51
* * *
WINDOWS 10 特殊问题 (2015)
# 游戏开发 - 使用 Unity 为通用 Windows 平台编写游戏
作者 [Jaime Rodriguez](https://msdn.microsoft.com/zh-cn/magazine/mt149362?author=Jaime+Rodriguez)、[Brian Peek](https://msdn.microsoft.com/zh-cn/magazine/mt149362?author=Brian+Peek) | Windows 2015
Windows 10 为游戏开发者和玩家提供了许多新功能。借助通用 Windows 平台 (UWP),开发者可以使用一段基本代码来定位 Windows 10 平板电脑和 PC、Windows 10 移动设备(即手机)、Xbox One 和 HoloLens。此外,我们还已将 Windows 应用商店融合为一,且 Microsoft 已在 Windows 10 中引入了 Xbox Live 服务以及 Xbox 应用,以提高玩家跨所有 Windows 设备系列的参与度。
对于游戏开发者,Unity 是最常用的游戏开发引擎之一。它支持 21 个平台,提供了目前所有可用中间件的最佳跨平台开发支持。结合 C# 脚本支持,它的编辑器可以实现极高效率的游戏开发环境。资产应用商店、Unity 社区以及 Unity 不断增加的广告、互动和分析功能让沉浸式游戏的开发变得空前容易。
一切进展得都十分顺利,我们必须写下来! 本文介绍了让 Unity 游戏在 Windows 10 上完美运行您所需知道的全部详情。这并非是对 Unity 或 UWP 应用的简单介绍。要理解本文的内容,您需要熟悉这两个主题。相反,我们将重点介绍 Windows 10 的变化,以及创建精彩的通用 Windows 游戏 (UWG) 的必知提示和技巧。为此,我们将以实战方式进行介绍,逐个讲解我们为了优化 Chomp 这一示例游戏(见图 1)以适应 Windows 10 所做的一些更改。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-08_568f407191768.png)
图 1:Chomp
Chomp 最初是一款使用 Unity 进行编写的 Windows 8.1 游戏。从图 1 中的屏幕截图可以看出,它是一款相当小型的迷宫游戏,类似于 Pac-Man。此示例旨在为开发者提供指导,向他们展示如何使用 Unity 编写游戏,因此简明易懂就很关键。不过,随着 Windows 10 的推出以及 Unity 支持新的操作系统,我们不得不对 Chomp 进行更新。有关 Chomp 的源代码,请访问 [bit.ly/UnityChomp](http://bit.ly/UnityChomp)。请下载源代码,并在我们的演示过程中继续参考。
若要获取游戏的 UWP 版本,我们只需使用 Unity 中的 Windows 10 配置文件,即可导出游戏,但这样做无法生成针对 Windows 10 运行方式优化的应用程序。它无法在全屏窗口模式下运行,也无法供用户触控等。那么,接下来就看看我们是如何将这款游戏从 Windows 8.1 迁移到 Windows 10 的。
## 入门(前提条件)
UWP 应用(和 UWG)要求您使用 Windows 10 和 Visual Studio 2015 进行开发和测试。所有 Visual Studio 2015 版本都会为您提供创建游戏所需的一切功能,包括免费的 Visual Studio Community 2015!
在 Unity 方面,您需要获得 Unity 5.2.1p2 或更高版本。Unity 5.2 现在安装有 Visual Studio Community 2015 和 Visual Studio 2015 Tools for Unity (VSTU)。因此,在实践中,您只需安装 Unity,并在安装过程中选择正确的选项即可入门。有关详情,请参阅图 2。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-08_568f4071dde43.png)
图 2:只需安装 Unity 并选择正确的选项即可入门
注意: 对于使用 Mac 的开发者,新的备选方法是对 Unity 项目使用 Visual Studio Code 编辑器。有关此选项的更多详细信息,请访问 [bit.ly/UnityVSCode](http://bit.ly/UnityVSCode)。
## 针对 Windows 10 构建
针对 Windows 10 构建的过程与您熟悉的过程完全相同。新增的 SDK 可以将 UWP 应用定位到 Windows 应用商店平台(见图 3)下,从而将游戏导出为 UWP 应用。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-08_568f407210788.png)
图 3:在 Unity 中定位 Windows 10
对于 Windows 10 和 UWP 开发,导出期间后台发生了下面一些重要变化:
* 您可以使用新增的 UNITY_UWP 和 UNITY_WSA_10_0 预处理器,调整游戏的 UWP 逻辑和体验。
* Unity 5.2 现在包含全新的简化 WinRTLegacy DLL,其中所含的类型比旧版更少。有了 Windows 10,Microsoft 已将多个类型重新引入 .NET Core 配置文件,导致 WinRTLegacy 中包含的某些解决方法不再是必需方法。
* Unity 5.2 使用的是 Unity 5 中引入的全新插件模型。这极大地简化了参与工作流的插件,本文后面对此进行了介绍。
* Unity 5.2 包括对 DirectX 12 的实验支持(Windows 10 自带)。若要尝试实验支持,请打开 Unity 中的“播放器设置”,取消选中“自动图形 API”选项,然后手动添加 Direct3D12 支持。
## 新项目模板
Unity 构建过程现在会生成与 UWP 兼容的 Visual Studio 2015 项目。您可能已经知道,这一全新的项目系统具有一些显著变化。
例如,每个 UWP 应用现在都自带各自的 .NET Core 副本,因此您始终可以获取用来测试的 .NET 版本。为了适应此变化,Unity 会生成相应的 project.json 文件。此文件会通过 NuGet 来提取合适的 .NET 部分。
此外,UWP 应用使用的是 .NET 本机,这样可以在将应用下载到客户计算机之前生成优化的本机计算机代码,并缩短启动时间,同时降低游戏的耗电量。虽然这些优化的影响因游戏的复杂程度而异,但是绝对不会影响性能的。唯一需要注意的是,.NET 本机确实会(显著)延长 Visual Studio 内的编译时。对于常规应用,Visual Studio 使用 .NET 本机仅编译项目的“发布”配置。对于 Unity 生成的项目文件,实现的是类似方法,仅“主机”配置是使用 .NET 本机进行编译。如果您不熟悉 Unity 中的配置目标,请参阅下文,配置目标分为三种:
* 调试配置是不含优化的完整调试项目。
* 发布配置是含优化的编译项目,但也包含探查器支持。
* 主机配置是您应提交给应用商店的配置。由于不含调试代码,因此所有优化都会启用,并且分析支持会遭删除。
您绝对应该在开发周期的早期使用 .NET 本机进行编译和测试。Unity 可以编辑许多高级中间语言 (IL)。因此,如果有可以充分利用 .NET 本机的应用类型,那一定就是 Unity 游戏。为了确保达到预期效果,请在 .NET 本机编译期间注意输出窗口中的警告。
虽然之前提到的区别在运行时非常显著,但新的 Unity 模板让这些变化对开发者一目了然,因此我们要重点介绍的是如何调整和优化 Windows 10 游戏。
## 调整和优化 Windows 10 游戏
跨多个外形规格的一段基本代码是 UWP 的重要特性,但提到游戏,可能仍有必要针对特定的外形规格进行一些调整和优化。最常见的调整和优化包括:输入机制(如触控、键盘、鼠标和游戏板);窗口重设大小;优化资源和资产;以及对每个特定外形规格实现本机平台集成(如动态磁贴、通知或 Cortana)。我们将探讨与 UWG 相关的调整和优化。
窗口化:通用 Windows 应用现在托管在可重设大小的窗口中,而不是像在 Windows 8 和 8.1 中一样以全屏模式运行。因此,可以考虑对游戏和应用程序使用窗口化。其中大多数区别对 Unity 开发者来说都一目了然,因为 Screen.height 和 Screen.width 属性仍可报告本机(像素)尺寸的可用空间。
Windows 10 还新增了用于进入和退出全屏的 API,设置 Screen.fullScreen 属性后可通过 Unity 屏幕类来公开这些 API。窗口化的最佳做法是实现标准键加速器,以进入和退出全屏。虽然最佳做法在发布服务器中的差异很大,但进入和退出全屏的常用加速器是 F11 或 Alt+Enter。对于 Chomp,我们想为玩家提供此选项以便他们可以全屏玩游戏,因此我们通过以下方式切换全屏模式:
~~~
if (Input.GetKeyUp (KeyCode.F11))
{
Screen.fullScreen = !Screen.fullScreen;
}
if (Input.GetKeyUp (KeyCode.F11))
{
Screen.fullScreen = !Screen.fullScreen;
}
~~~
配备多窗口桌面需要对 Windows 10 游戏进行另一项更改: 必须处理焦点变化。在多窗口桌面中,如果您的游戏窗口没有焦点,那么您应暂停游戏和音乐,因为用户可能在与其他窗口进行交互。Unity 使用在其他平台中公开的同一 API 对此交互进行抽象:OnApplicationPause 方法。当焦点变化时,系统会对所有有效的 MonoBehaviours 调用此方法。我们在 Chomp 中对此进行处理,如图 4 所示。
图 4:当焦点变化时暂停游戏
~~~
public void OnApplicationPause(bool pause)
{
FocusChanged(!pause);
}
public void FocusChanged(bool isFocused)
{
if (isFocused)
musicSource.UnPause();
else
{
musicSource.Pause();
GameState.Instance.SetState(GameState.GameStatus.Paused);
}
}
~~~
请注意以下不对称性: 当游戏失去焦点时,游戏和音频会暂停,但在游戏获得焦点时,我们只会取消暂停音频。这是因为,当游戏暂停时,我们还会在游戏本身中显示一个暂停的对话框;在焦点恢复时,游戏会等待用户确认是否要继续玩游戏。此对话框用于将游戏状态从“暂停”设置回“正在运行”。
在执行这两项更改后,我们可以正确处理进入/退出全屏,以及在窗口失去焦点时暂停游戏。
输入:旧版 Unity 非常支持 Windows 游戏输入,这一点在 Windows 10 中保持不变。Unity 中的输入类和输入管理器仍可方便地对鼠标、触控和游戏板进行抽象。
关于输入最重要的一点是,确保实现尽可能多对游戏有意义的输入机制。对于 Chomp,我们希望支持键盘、游戏板和触控。请注意,由于 UWG 可以在任意位置上运行,因此尽可能为玩家提供最佳输入/游戏体验。有关输入的最常见问题是,如何检测您是否需要在使用触控设备(如手机)时显示触控控件(如虚拟游戏杆或方向键)。
确定是否应显示触控游戏杆的一种方法是,确定游戏是否是在手机上运行。如果是,可以默认显示并启用游戏杆。若要确定游戏是否是在特定平台(如手机或 Xbox)上运行,您可以检查是否实现了相应的协定。下面介绍了 Chomp 如何检测自身是否是在 Windows 10 移动版上运行:
~~~
public static bool IsWindowsMobile
{
get
{
#if UNITY_WSA_10_0 && NETFX_CORE
return Windows.Foundation.Metadata.ApiInformation.
IsApiContractPresent ("Windows.Phone.PhoneContract", 1);
#else
return false;
#endif
}
}
~~~
请注意,在此代码中,我们使用 UNITY_WSA_10_0 预处理器来确定我们是否针对 Windows 10 进行编译。如果未执行此检查,则代码将无法在非 Windows 10 版本上进行编译。
虽然始终显示虚拟游戏杆是一种方法,但最好只当用户在设备上实际使用的是触控时才显示游戏杆。Windows 10 新增的 API 可以确定用户是在平板电脑模式(触控)下还是在传统桌面模式(鼠标/键盘)下运行 Windows 10: Windows.UI.ViewManagement.UIViewSettings.UserInteractionMode。此 API 必须在 Windows UI 线程上运行,因此必须从 Unity 内部封送对 UI 线程的调用。我们已向 Chomp 添加了图 5 中的代码,以确定用户是否在使用触控与应用进行交互。
图 5:确定用户是否在使用触控的代码
~~~
public static bool IsWindows10UserInteractionModeTouch
{
get
{
bool isInTouchMode = false;
#if UNITY_WSA_10_0 && NETFX_CORE
UnityEngine.WSA.Application.InvokeOnUIThread(() =>
{
isInTouchMode =
UIViewSettings.GetForCurrentView().UserInteractionMode ==
UserInteractionMode.Touch;
}, true);
#endif
return isInTouchMode;
}
}
~~~
现在,我们已实现了这两种方法,可以更新 Chomp 以更为完善地估算游戏杆的显示时间了。如果游戏是在移动设备上运行,或用户交互模式是触控,则 UseJoystick 会返回 true,然后我们会显示游戏杆:
~~~
public static bool UseJoystick
{
get
{
return (IsWindowsMobile || IsWindows10UserInteractionModeTouch) ;
}
}
~~~
通过处理窗口化和输入,我们现在可以继续利用新本机 Windows API 来为游戏添加更多功能。
与 Windows 10 本机集成: 平台触发 - 从 Unity 游戏内与操作系统本机集成的处理方式与之前相同: 如果您要在 Unity 中使用 .NET Core 编译选项进行编译(使用 NETFX_CORE 预处理器),则可以内联本机代码,如前面的示例所示。
如果要添加的代码多于要内联的代码,或需要对行为进行抽象(跨平台),则您仍可以使用插件。对于 Windows 10,Microsoft 开发者体验游戏传播团队(我们属于这个团队)开放了多个新插件的源代码,以便您可以更轻松地与 Windows 10 集成。有关这些插件,请访问 [bit.ly/Win10UnityPlugins](http://bit.ly/Win10UnityPlugins)。目前,已共享以下插件:
* 应用商店: 适用于应用内购买的应用商店插件,支持应用模拟器、消费品、耐用品和收据。其中有您需要与 Windows 应用商店交易的任何内容。
* AzureMobile: Microsoft Azure 插件,可执行 Azure 存储空间的创建、读取、更新和删除 (CRUD) 基本操作。
* 核心: 提供与核心操作系统功能(如动态磁贴、本地通知、推送通知和 Cortana)的本机集成的“核心”插件。
* 广告: 封装新的 Windows 10 Microsoft 广告 SDK 的插件,现在支持视频插页式广告。
以前,Chomp 不含应用内购买,因此我们决定了使用应用商店插件向游戏添加应用内购买。现在,Chomp 支持购买消费品(增强程序)和耐用品(迷宫)。
使用这些插件的最简单方法是,从 GitHub 下载 Unity 包,然后使用 Unity 编辑器中的“资产 | 导入包 | 自定义包”将此包导入 Chomp。在您导入包后,Unity 的“插件”文件夹中包含正确的二进制文件。安装后,这些二进制文件位于“插件\WSA”目录中;Unity 需要在编辑器内使用占位符程序集(与 Microsoft .NET Framework 3.5 兼容),因此这些程序集也会纳入和复制到“插件”文件夹本身中。
在您导入包后,我们现在可以从 Chomp 内引用应用商店 API。我们先调用 Store.LoadListingInformation,提供在完成后立即运行的回叫方法,以获取可以购买的所有项目的列表。如果调用成功,则我们会循环访问返回的 ProductListing 项目,然后使用这些项目来填充 UI 中的价格,如图 6 所示。
图 6:列出可以进行应用内购买的项目
~~~
void Start()
{
Store.LoadListingInformation(OnListingInformationCompleted);
...
}
void OnListingInformationCompleted(
CallbackResponse<ListingInformation> response)
{
if (response.Status == CallbackStatus.Success)
{
ListingInformation result = response.Result;
PopulatePrices(result.ProductListings);
}
}
~~~
在用户选择了要购买的项目后,只需再添加几行代码即可执行交易。图 7 展示了我们添加用来购买耐用品(游戏的新迷宫)的代码。
图 7:执行应用内购买
~~~
public void OnDurablePurchase(GameObject buttonClicked)
{
string productId = GetProductId(buttonClicked.name);
if (!string.IsNullOrEmpty (productId))
{
Store.RequestProductPurchase(productId, (response) =>
{
if (response.Status == CallbackStatus.Success)
{
// response.Status just tells us if callback was successful.
// The CallbackResponse tells us the actual Status
// as returned from store.
// Check both.
if (response.Result.Status == ProductPurchaseStatus.Succeeded)
{
EnableLevels(productId);
return;
}
}
});
}
}
~~~
如您所见,使用这些新插件实现本机功能很简单。
## 提交至应用商店
提交至 Windows 应用商店不再是难事。您现在可以提交一个包含所有二进制文件的包,也可以为每个平台/体系结构都提交一个包(如果需要)。
如果您想拆分包或仅在特定平台上支持游戏,则可以手动编辑 package.appxmanifest 文件,并调整 TargetDeviceFamily 元素:
~~~
<Dependencies>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.10240.0"
MaxVersionTested="10.0.10240.0" />
</Dependencies>
~~~
三种可能的设备系列:
* Windows.Universal: 方便您在满足硬件要求的所有位置上部署二进制文件。
* Windows.Mobile: 应该对进入 Windows 10 移动版 SKU(即 Windows Phone)的二进制文件使用,尽管将来可能有其他并非手机但运行此 SKU 的小型设备(六英寸或更小),因此请勿假设只有手机。
* Windows.Desktop: 应对只能在桌面设备和平板电脑上运行的游戏使用。
如果您想定位移动设备和桌面设备,而不是控制台或其他更高版本的 Windows 系列,则可以在清单中添加两个设备系列(替换相应的“x”和“y”)。
~~~
<Dependencies>
<TargetDeviceFamily Name="Windows.Mobile" MinVersion="10.0.x.0"
MaxVersionTested="10.0.y.0"/>
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.x.0"
MaxVersionTested="10.0.y.0"/>
</Dependencies>
~~~
请注意,每个设备系列均可以有不同的 MinVersion 和 MaxVersion。将来会很方便,因为 Windows 10 移动版将自带版本号高于 Windows 10 的桌面版。不过,目前我们建议您保留默认版本 (10.0.10240.0)。
如我们之前在讨论 .NET 本机时所述,提交包时应务必提交主机配置。此外,我们还建议您添加完整的程序数据库 (PDB) 符号文件进行故障分析。新的应用商店不提供下载 cab 文件进行本地分析的选项。相反,您必须将 PDB 提交至 Windows 应用商店,然后应用商店会为您完成相关工作,同时提供故障的堆栈跟踪(见图 8)。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-08_568f407249ba8.png)
图 8:添加程序数据库符号文件
最后,当您通过开发者门户提交至 Windows 应用商店时,请务必选择正确的硬件配置。应用商店现在允许您指定硬件要求(如触控或键盘),以便游戏只在正确的设备上安装(见图 9)。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-08_568f4072723cf.png)
图 9:开发者门户中的硬件首选项
## 相关内容还有很多!
本文通过展示我们如何将简单的游戏移植到了 Windows 10 中以及如何添加了一些新功能,概述了面向 Unity 开发者的“新增功能探秘”。在有限的篇幅内,我们重点介绍了基础知识和游戏的“必做之事”,而不是向您展示 Windows 10 平台中的每个新功能。如果您想开发酷炫的沉浸式游戏,请考虑利用其他功能,如桌面上的新通知中心(旨在提高参与度)、Cortana、新动态磁贴模板和新 Xbox Live 服务 API。借助 Windows 10,Microsoft 正在逐步开放对 Xbox Live 服务的访问。您无需编写控制台游戏,只需有在 Windows 10 上运行的酷炫游戏,并希望利用排行榜、成就、跨设备运行等服务即可。若要申请访问权限,请注册 ID@Xbox 计划(网址为 [xbox.com/id](http://xbox.com/id))。
### Visual Studio 2015 Tools for Unity
对于第 5.2 版及更高版本,Unity 包括 Visual Studio 2015 Tools for Unity (VSTU),让 Visual Studio 成为 Windows 上 Unity 项目的新默认代码编辑器。此变化将带来改进后的 IntelliSense、编辑器中的语法着色,以及出色的 C# 调试程序。若要配置默认的脚本编辑器,请选择 Unity 编辑器中的“编辑 | 首选项”菜单选项。您可以选择 MonoDevelop(内置)、Visual Studio 2015、Visual Studio 2013,也可以选择浏览更多选项。
VSTU 也包括一些快捷方式,以便您可以更轻松地编写 Unity 代码。例如,如果您在 MonoBehaviour 类中右键单击,则上下文菜单会显示新的“实现 MonoBehaviours”条目,以便您可以快速地将 MonoBehaviour 方法签名插入类。
相同的上下文菜单中还包含“快速 MonoBehaviours”条目,以便您可以执行类似功能(但您会看到一个干扰程度较低的对话框,您可以在其中键入要搜索的方法名称),然后即可再次插入签名。以上两种方法均可通过快捷键加速器使用,以提高使用速度(Ctrl+Shift+M 和 Ctrl+Shift+Q)。
除了编辑器增强功能之外,使用 VSTU 时的最佳功能之一就是,简化了与 Unity 编辑器的调试程序集成。在 Visual Studio 中打开 Unity 项目时,您会自动看到“附加到 Unity”按钮(用于在标准调试工具栏进行调试)。图 A 展示了此按钮的位置。此按钮会自动查找 Unity 编辑器的进程并附加到其中。从此,您可以顺畅设置断点、分析变量值,并能执行其他所有大部分的 Visual Studio 预期操作。VSTU 甚至包括对中断异常的实验支持。有关 VSTU 2.0 功能的更多详细信息,请查看博客文章“Visual Studio Tools for Unity 2.0”([bit.ly/VSTUInfo](http://bit.ly/VSTUInfo))。
注意: 如果您定位的不是 Windows 10,也没有使用 Visual Studio 2013 ,则可通过可下载的包将此处所述的全部优势带给 Visual Studio 2013 社区版用户。您可以访问 [bit.ly/VSTU2013](http://bit.ly/VSTU2013),下载此扩展程序。
* * *
Jaime Rodriguez *是 Microsoft 开发者体验游戏传播团队的负责人。您可以通过以下方式与他联系:Twitter [@jaimerodriguez](https://twitter.com/@jaimerodriguez) 和博客 [jaimerodriguez.com](http://jaimerodriguez.com/)。*
Brian Peek *是 Microsoft 高级游戏开发者传播团队成员。他是一位资深玩家,自有记忆起他便在 Windows、控制台以及其他任何可以编程的平台上开发游戏。您可以在开发者会议的全国巡讲中看到他,也可以通过以下方式关注他:Twitter [@BrianPeek](https://twitter.com/@BrianPeek) 和博客 [brianpeek.com](http://brianpeek.com/)。*
数字墨迹 – Windows 10 中的墨迹交互
最后更新于:2022-04-01 06:55:49
WINDOWS 10 2015 年特别版
此文章由机器翻译。
# 数字墨迹 - Windows 10 中的墨迹交互
通过 [Connor Weins](https://msdn.microsoft.com/zh-cn/magazine/mt149362?author=Connor+Weins) |Windows 2015 年
在本文中,我将介绍如何将提升自然的用户交互使用墨迹书写。数字墨迹,很像在纸上、 笔从您的数字笔设备、 笔针、 手指或鼠标的提示将排并呈现在屏幕上。若要获取开始与数字墨迹和手写 Windows 10 中,我将首先通过解决基本问题: 为什么是您必须在您的应用程序中使用墨迹?
人类具有已传达的想法和创意通过手写世纪。尽管鼠标和键盘的发明,笔和纸方法仍扮演着关键角色在我们的生活中 — 从粘滞便笺的步骤和我们的办公室中我们学校笔记本和我们的孩子他人之手着色丛书中的白板。
笔和纸是即时、 自由格式且唯一个人到我们每一个人,这使得用户可利用来表示他们的创造力和情感的理想选择。将想法转换成文本和到笔记的关系图的 act 还会使手写更适合进行思考、 记忆和学习,根据 2013年研究发布到心理科学中 ([bit.ly/1tKDrhv](http://bit.ly/1tKDrhv))、 从普林斯顿和 UCLA 研究人员在其中找到手写的便笺已明显优于类型化的说明为长期的理解。
与传统的类型化的键盘输入的墨迹这些优点,设想一下是否您可能会使手写笔和纸和工具一样容易的设备上的计算机的处理能力来执行现实生活中您不能执行的操作。使用数字墨迹,您可以轻松地改变颜色和墨迹的外观就像在现实生活中,而采用其基础上更进一步、 分析的内容和形状的手写内容来提供元数据,或将墨迹转换为其他内容,如文本、 图形或命令。它提供了您的日常 notebook,使数字墨迹绘图、 笔记记录批注以及在您的应用程序进行交互的功能强大的工具不能复制到的墨迹书写的全新维度。随着支持笔和触摸的设备市场不断扩大,墨迹书写将成为用户和应用程序开发人员交互的一个关键方法。
在 Windows 10 中,是便于您能够将您的应用程序通过 DirectInk 平台到数字墨迹书写。DirectInk 提供了一套丰富且可扩展 Windows 运行时 (WinRT) 允许您收集、 呈现和管理在通用 Windows 平台应用程序中的墨迹的 Api。通过使用 DirectInk,您可以获得的同一个很好的手写内容和 Microsoft 边缘浏览器,通用 OneNote 和手写板使用的性能。下面是 DirectInk 提供您的应用程序的功能的快速概述:
* 既美观又具备手写内容: DirectInk 使用输入平滑处理并贝塞尔呈现算法以确保您的手写内容始终看起来清晰和漂亮的触摸和笔输入。
* 低延迟、 内存不足: DirectInk 使用高优先级后台线程和输入的预测以确保手写内容始终是即时且对用户的响应能力和它所管理资源,有效地以保持您的应用程序开销较低。
* 简单而又可扩展的 API 图面: DirectInk 提供了 Api (如 InkCanvas 和 InkPresenter,允许您快速地开始收集和管理墨迹,并提供允许您构建您的应用程序中的丰富而复杂的功能的高级的功能。
希望目前为止您非常高兴地开始在您的应用程序中使用数字墨迹。现在将一看如何在您的应用程序中利用 DirectInk 平台并为用户提供更完美的墨迹书写体验。
## 收集应用程序中的墨迹
若要开始使用数字墨迹,第一步是设置了一个可以收集和呈现为墨迹输入面。在 Windows 8.1 应用商店应用程序中引入到您的应用程序的墨迹书写时涉及到创建一个画布,侦听事件,以及如何创建和呈现笔画--逐一使用您自己的呈现代码输入一个扩展的过程。对于通用 Windows 应用程序,以收集手写内容的开头是像将 InkCanvas 放到您的应用程序一样简单:
~~~
<Grid>
<InkCanvas x:Name="myInkCanvas"/>
</Grid>
~~~
如您所见中 图 1, ,这行代码为您提供开始收集的笔输入和输入为黑色圆珠笔的呈现的透明覆盖。将笔橡皮擦按钮还将擦除它自带联系任何收集的手写内容。尽管这是很好的入门知识的墨迹书写,如果想要更改墨迹收集或显示如何?
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-08_568f407143fc9.png)
图 1 使用 InkCanvas 以收集手写内容类似于黑色圆珠笔
通过 InkCanvas,您可以访问您的 InkPresenter,公开用于控制外观和墨迹的输入的配置的功能。虽然笔输入提供了最佳的用户体验的墨迹书写,许多系统不会配备用笔。只需将会收集笔、 触摸和鼠标输入和您没有选择的输入的类型的任意组合的墨迹 InkPresenter 允许传递作为到 InkCanvas XAML 元素的指针事件。通过 InkPresenter,还可以管理绘图的墨水在 InkCanvas,从而允许您更改画笔大小、 颜色及更多内容上收集的属性的默认值。这些功能的示例,作为您的应用程序可以将配置您 InkCanvas 以收集手写笔、 触摸和鼠标输入,并通过执行以下操作模拟书法画笔:
~~~
InkPresenter myPresenter = myInkCanvas.InkPresenter;
myPresenter.InputDeviceTypes = Windows.UI.Core.CoreInputDeviceTypes.Pen |
Windows.UI.Core.CoreInputDeviceTypes.Touch |
Windows.UI.Core.CoreInputDeviceTypes.Mouse;
InkDrawingAttributes myAttributes = myPresenter.CopyDefaultDrawingAttributes();
myAttributes.Color = Windows.UI.Colors.Crimson;
myAttributes.PenTip = PenTipShape.Rectangle;
myAttributes.PenTipTransform =
System.Numerics.Matrix3x2.CreateRotation((float) Math.PI/4);
myAttributes.Size = new Size(2,6);
myPresenter.UpdateDefaultDrawingAttributes(myAttributes);
~~~
程序将生成结果中所示 图 2。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-08_568f40715c4e9.png)
图 2 模拟书法画笔使用 InkPresenter DrawingAttributes
DirectInk 支持许多内置了更多配置输入和手写内容呈现允许您呈现作为荧光笔墨迹、 接收事件收集笔画时、 访问细粒度的输入的事件和墨迹具有高级配置中的多个指针。
## 编辑、 保存和加载墨迹
因此既然您已经收集一些墨迹,什么您如何使用它? 用户经常需要擦除或编辑的墨迹收集它们,或保存以后访问该手写内容的能力。为了给您的用户提供这种体验,您必须以访问和修改 DirectInk 已呈现在屏幕的笔画的墨迹数据。
在您 InkCanvas 上不会收集手写内容,DirectInk 内 InkPresenter InkStrokeCollection 内存储它。此 InkStrokeCollection 包含 WinRT 对象来表示每个当前在您画布上的笔画和更改对此容器进行了您的应用程序,它们将还将呈现在屏幕上。这允许您以编程方式添加、 删除或修改笔画,并允许 DirectInk 可帮助您了解到在屏幕上的笔画它做的任何更改。让我们看看一些常见的用户交互可以实现使用 InkPresenter 和其 InkStrokeContainer 之间的连接。
Erasing 虽然 InkCanvas 支持擦除使用笔橡皮擦按钮默认情况下,但它需要在 InkPresenter 清除墨迹的鼠标和触摸输入一些配置。DirectInk 提供内置支持擦除通过 InputProcessingConfiguration 中的模式属性的任何受支持的输入的墨迹。下面是举例说明如何将 Erasing 模式设置为一个按钮:
~~~
private void Eraser_Click(object sender,
RoutedEventArgs e)
{
myInkCanvas.InkPresenter.
InputProcessingConfiguration.Mode =
InkInputProcessingMode.Erasing;
}
~~~
按下此按钮时,DirectInk 收集 InkCanvas 的所有输入将被都视为橡皮擦。如果设置此模式后,用户输入与笔画相交,则将从 InkPresenter InkStrokeContainer 中删除该笔划,并将其从屏幕上删除。当使用笔墨迹书写模式下的,橡皮擦按钮将始终被视为擦除模式。
选择 遗憾的是,DirectInk 不具有对这一次,在内置的选定内容的支持,但它确实提供了一种方法来通过未处理的输入事件自己开发。只要 DirectInk 收到告诉侦听,但不是能呈现到墨迹输入引发未处理的事件。这可以通过设置处理配置模式下为无 DirectInk 完成对所有输入并还可以配置为发生这种情况仅用于鼠标右按钮和笔笔杆按钮使用 RightDragAction 属性:
~~~
myInkCanvas.InkPresenter.InputProcessingConfiguration.RightDragAction =
InkInputRightDragAction.LeaveUnprocessed;
~~~
例如, 图 3 显示了如何使用未处理的输入事件以使所选内容套索 (如中所示 图 4) 选择在屏幕上的笔画。
图 3 使用未处理的输入的事件以使所选内容套索
~~~
...
myInkCanvas.InkPresenter.UnprocessedInput.PointerPressed += StartLasso;
myInkCanvas.InkPresenter.UnprocessedInput.PointerMoved += ContinueLasso;
myInkCanvas.InkPresenter.UnprocessedInput.PointerReleased += CompleteLasso;
...
private void StartLasso(
InkUnprocessedInput sender,Windows.UI.Core.PointerEventArgs args)
{
selectionLasso = new Polyline()
{
Stroke = new SolidColorBrush(Windows.UI.Colors.Black),
StrokeThickness = 2,
StrokeDashArray = new DoubleCollection() { 7, 3},
};
selectionLasso.Points.Add(args.CurrentPoint.RawPosition);
AddSelectionLassoToVisualTree();
}
private void ContinueLasso(
InkUnprocessedInput sender, Windows.UI.Core.PointerEventArgs args)
{
selectionLasso.Points.Add(args.CurrentPoint.RawPosition);
}
private void CompleteLasso(
InkUnprocessedInput sender, Windows.UI.Core.PointerEventArgs args)
{
selectionLasso.Points.Add(args.CurrentPoint.RawPosition);
bounds =
myInkCanvas.InkPresenter.StrokeContainer.SelectWithPolyLine(
selectionLasso.Points);
DrawBoundingRect(bounds);
}
~~~
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-08_568f407179cf5.png)
图 4 选择使用套索笔画
您选择的笔画后,可以使用 InkStrokeContainer.MoveSelected 方法来转换笔画,或使用 InkStroke.PointTransform 属性将仿射转换应用于这些笔画。以这种方式转换描边或笔画 InkStrokeContainer 由管理组时, DirectInk 将拾取这些更改并呈现到屏幕。
保存和加载 DirectInk 本身支持手写内容保存并加载通过墨迹序列化格式 (ISF),它将手写内容保存在矢量格式使其成为共享和编辑、 更简单。这是通过 InkStrokeContainer SaveAsync 和 LoadAsync 函数可访问。
SaveAsync 采用当前存储在 InkStrokeContainer 的笔画数据并将其保存为 GIF 文件与嵌入 ISF 数据。图 5 演示如何将手写内容保存从您 InkStrokeContainer。
图 5 将手写内容保存从 InkStrokeContainer
~~~
var savePicker = new FileSavePicker();
savePicker.SuggestedStartLocation =
Windows.Storage.Pickers.PickerLocationId.PicturesLibrary;
savePicker.FileTypeChoices.Add("Gif with embedded ISF",
new System.Collections.Generic.List<string> { ".gif" });
StorageFile file = await savePicker.PickSaveFileAsync();
if (null != file)
{
try
{
using (IRandomAccessStream stream =
await file.OpenAsync(FileAccessMode.ReadWrite))
{
await myInkCanvas.InkPresenter.StrokeContainer.SaveAsync(stream);
}
}
catch (Exception ex)
{
GenerateErrorMessage();
}
}
~~~
LoadAsync 将执行相反的函数中,清除已在您 InkStrokeContainer 笔画,并从 ISF 文件或 GIF 文件与嵌入 ISF 数据加载一组新的笔画。笔画载入 InkStrokeContainer 后,DirectInk 自动将呈现它们在屏幕上。
## 高级墨迹书写功能
开发带有手写内容的用户交互的关键能够编辑和处理在屏幕上的手写内容时,它可能不是不足以满足您的需要。更多创意希望您的应用程序以支持交互,您的应用程序将具有以中断的交互 DirectInk 提供了一组默认的越多。让我们深入了解 DirectInk 使您能够构建丰富而独特的手写功能的方式的少数几个:
墨迹书写识别 墨迹是不止是在屏幕上的像素。用户的墨迹可以解释为图片、 关系图、 形状或文本。识别用户的墨迹的内容,可将手写内容相关联以致其意义或交换与它所代表的内容的墨迹。例如,如果用户在笔记记录应用程序中编写文本,您的应用程序可以识别手写内容表示,用于当用户搜索栏中输入一个查询时生成搜索结果中使用该文本数据的文本。InkRecognizerContainer 供电意识到这种方式中的文本。图 6 演示如何使用 InkRecognizerContainer 以将手写内容解释为简体中文字符。
图 6 使用 InkRecognizerContainer 简体中文字符作为解释笔迹
~~~
async void OnRecognizeAsync(object sender, RoutedEventArgs e)
{
InkRecognizerContainer recoContainer = new InkRecognizerContainer();
IReadOnlyList<InkRecognizer> installedRecognizers =
recoContainer.GetRecognizers();
foreach (InkRecognizer recognizer in installedRecognizers)
{
if (recognizer.Name.Equals("Microsoft 中文(简体)手写识别器"))
{
recoContainer.SetDefaultRecognizer(recognizer);
break;
}
}
var results = await recoContainer.RecognizeAsync(
myInkCanvas.InkPresenter.StrokeContainer,InkRecognitionTarget.All);
if (results.Count > 0)
{
string str = "Result:";
foreach (var r in results)
{
str += " " + r.GetTextCandidates()[0];
}
}
}
~~~
而这将允许你将手写内容识别为文本,InkRecognizerContainer 在于它当前支持从仅 33 不同的语言包的识别文本有限制。如果您想要识别从另一种语言的文本或识别符号、 图形或其他更抽象的墨迹解释,您需要构建该逻辑从零开始。幸运的是,该 InkStroke 对象所提供 GetInkPoints 函数,使你能获取 x / y 位置的每个输入点用于构造与笔画。据此,您可以构建一种算法来分析笔划的输入的点或一组笔划并随意对其进行解释 — 为符号,形状、 命令或您的想象力的任何能想到的 !
独立输入 DirectInk 是一种功能强大的引擎为在一组简单的输入的规则下运行的呈现墨迹 — 呈现一个给定的笔划的墨迹或不。若要使此决定,它看起来在受支持的输入的类型的输入处理模式提供配置和右拖放操作配置。这缺少了大量您的应用程序可能想要提供的墨迹书写的上下文 — 您的应用程序可能不允许在画布上的某些部分中的墨迹书写或可能有手势的墨迹书写应在停止后识别出的笔势。若要启用您做出这样的决策,DirectInk 提供输入之前它将开始处理通过独立输入事件的访问权限。这些事件使您能够之前 DirectInk 因此如果不允许的墨迹书写区域或完成手势移动事件中收到一个按下的事件您期盼已久的只是可以将标记该事件作为 Handled 已呈现它,检查输入。
DirectInk 时该事件被标记为 Handled,将停止处理笔画,并且如果一个笔划已过程中,它将取消并从屏幕上删除。您需要时使用这些事件,但请务必小心。它们而不是 UI 线程的 DirectInk 后台线程上发生了,因为任何处理工作繁重您在执行操作的事件或等待如 UI 线程可能会引入会影响您的手写内容的响应能力的滞后时间在速度较慢的线程中运行的活动。
自定义干 DirectInk 最复杂的功能之一是烘干自定义的模式,它允许您的应用程序来呈现和管理已完成或"干"墨迹笔画时让 DirectInk 处理正在进行的高性能呈现、 您自己 DirectX 表面上或"湿"墨迹笔画。虽然 DirectInk 的默认烘干模式可以处理大多数情况下可能需要在您的应用程序中启用,但是了几种方案需要您可以独立地管理墨迹:
* 在保持 z 顺序的同时交替墨迹和非手写内容 (文本、 形状)
* 高性能平移和缩放到大型墨迹画布上具有大量墨迹笔画
* 转换为直线或形状类似的 DirectX 对象以同步方式烘干墨迹
在 Windows 10 自定义烘干模式支持与 SurfaceImageSource (SIS) 或 VirtualSurfaceImageSource (VSI) 同步。SIS 和 VSI 提供您的应用程序绘制到和撰写,DirectX 共享图面虽然 VSI 提供了虚拟的表面大于平移和缩放的高性能的屏幕。当手写内容呈现到 SIS 或 VSI,视觉对象更新到这些表面会同步到 XAML UI 线程上,因为它可以删除从 DirectInk 湿层同时。自定义 Drying 也支持烘干墨迹转换为 SwapChainPanel 但并不能保证同步。因为 SwapChainPanel 不与 UI 线程同步的则将有之间小重叠时手写内容呈现给您 SwapChainPanel 而当从 DirectInk 湿手写内容图层中删除手写内容。
时您激活烘干自定义时,你会获得的许多功能都 DirectInk 提供默认情况下,允许您以构建呈现和从您干的图面中删除手写内容的方式的逻辑并确定如何将墨迹笔划数据管理您的应用程序的精细控制。为了帮助您生成此项功能,许多 DirectInk 组件都可用作独立对象以填充空白帮助您的应用程序。自定义烘干激活时,DirectInk 提供了一个 InkSynchronizer 对象,它允许您开始和结束烘干过程以便墨迹删除从 DirectInk 湿层与同步时将其添加到您的自定义干层。DirectInk 默认干墨呈现逻辑它也可通过 InkD2DRender 以确保墨迹外观湿和干层之间保持一致。有关擦除,可以使用未处理的输入事件生成擦除逻辑类似于前面的示例。
有关详细信息和使用自定义烘干的示例,请查看 ComplexInk 示例可在 GitHub 上 [bit.ly/1NkRjt7](http://bit.ly/1NkRjt7)。
## 开始创建具有墨迹
使用您已了解到目前为止有关 InkCanvas、 InkPresenter 和 InkStrokeContainer 中,您现在可以收集手写内容的不同类型的输入,自定义如何显示的墨迹在屏幕上访问笔画数据并具有对笔画数据的更改会反映在由 DirectInk 呈现墨迹笔划。与该简单级别的功能,您可以构建范围广泛的用户交互,从简单灵机一动详细专注于方案的功能,例如笔记记录和收集用户的签名。您还可以用于构建更复杂的交互通过 InkRecognizerContainer,独立的输入事件和自定义烘干模式下的工具。
使用可供您使用这些工具,您的应用程序应该能够利用所有数字墨迹可以提供给您的用户提供更完美的墨迹书写体验的优势。随着的笔和触控启用的设备数量不断增加,为客户提供更完美的墨迹书写体验将变得更为重要的用户的满意度和应用程序的区分作用。希望您可能需要一些时间想有关数字墨迹书写程序可以在您的应用程序中工作并开始试验 DirectInk。
最后请注意,墨迹书写仍然是 microsoft 的投资的重要区域以及对改进的最大密钥之一并展开针对将来版本的 DirectInk 平台是我们的开发人员社区的反馈。如果在使用 DirectInk 进行开发时有任何疑问、 意见或想法,请将它们发送到 [DirectInk@microsoft.com](mailto:DirectInk@microsoft.com)。
* * *
Connor Weins *是处理笔触笔和墨迹书写 Windows 开发人员生态系统平台组中的团队的项目经理。与他联系 [conwei@microsoft.com](mailto:conwei@microsoft.com)。*
UI 设计 – 适用于 Windows 10 的自适应应用
最后更新于:2022-04-01 06:55:46
WINDOWS 10 2015 年特别版
# UI 设计 - 适用于 Windows 10 的自适应应用
作者:[Clint Rutkas](https://msdn.microsoft.com/zh-cn/magazine/mt149362?author=Clint+Rutka) 和 [Rajen Kishna](https://msdn.microsoft.com/zh-cn/magazine/mt149362?author=Rajen+Kishna) | Windows 2015
通过使用 Windows 10 的通用 Windows 平台 (UWP),应用目前可在各种设备系列上运行,并在平台控件的支持下,在不同大小的屏幕和窗口中实现自动缩放。这些设备系列如何支持用户与您的应用程序之间的交互,您的应用程序如何响应并自适应于其运行所在的设备? 我们探讨这些问题以及 Microsoft 在该平台中提供的工具和资源,方便您不必再为了让应用程序能够运行在不同类型的设备上而编写和维护复杂代码。
让我们先来探讨可以用来优化不同设备系列的 UI 的响应技术。然后,再深入探讨如何使您的应用自适应特定的设备功能。
在深入探讨控件、API 和代码之前,我们先花点时间探讨一下目前谈到的设备系列。简而言之: 设备系列是指一组具有特定外形规格的设备,从 IoT 设备、智能手机、平板电脑和台式电脑到 Xbox 游戏控制台、大屏 Surface Hub 设备,甚至便携式设备。应用将在所有这些设备系列中运行,而在设计您的应用时,考虑将运行该应用的设备系列是一件很重要的事情。
虽然有许多设备系列,UWP 却设计为:让 85% 的 API 可以完全供任何应用访问,不受应用所运行位置的约束。此外,对于前 1,000 个应用,基础通用 Windows API 集中的 API 数量占所有已使用的 API 总数的 96.2%。提供大部分功能且这些功能可作为 UWP 的一部分,而每个设备上专用的 API 可用于进一步定制您的应用。
## 欢迎回来,Windows
“如何在 Windows 中使用应用”中的一个最大的变化是您已经很熟悉了的:在窗口中运行应用。Windows 8 和 Windows 8.1 允许应用全屏运行,或同时并排显示多达四个应用。相比而言,Windows 10 允许用户随意排列应用、重设应用大小和放置应用。Windows 10 中的新方法为用户提供了更加灵活的 UI,但可能需要您最终做一些工作来优化它。Windows 10 在 XAML 中所做的改进中引入了一些可以在您的应用中实现响应技术的方法,所以无论屏幕或窗口大小如何,看上去都很好。我们来探讨这三种方法。
VisualStateManager 在 Windows 10 中,VisualStateManager 类已扩展为两种机制,用于在基于 XAML 的应用中实现响应式设计。新 VisualState.StateTriggers 和 VisualState.Setters API 允许您定义符合一定条件的视觉状态。通过使用内置 AdaptiveTrigger 作为 VisualState 的 StateTrigger,并设置 MinWindowHeight 和 MinWindowWidth 属性,视觉状态就可以根据应用窗口的高度和宽度进行更改。您还可以对 Windows.UI.Xaml.StateTriggerBase 进行扩展以创建自己的触发器,例如触发设备系列或输入类型。请看一看图 1 中的代码。
图 1 创建自定义状态触发器
~~~
<Page>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState>
<VisualState.StateTriggers>
<!-- VisualState to be triggered when window
width is >=720 effective pixels. -->
<AdaptiveTrigger MinWindowWidth="720" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="myPanel.Orientation"
Value="Horizontal" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<StackPanel x:Name="myPanel" Orientation="Vertical">
<TextBlock Text="This is a block of text. It is text block 1\. "
Style="{ThemeResource BodyTextBlockStyle}"/>
<TextBlock Text="This is a block of text. It is text block 2\. "
Style="{ThemeResource BodyTextBlockStyle}"/>
<TextBlock Text="This is a block of text. It is text block 3\. "
Style="{ThemeResource BodyTextBlockStyle}"/>
</StackPanel>
</Grid>
</Page>
~~~
在图 1 示例中,页面将显示三个在默认状态下相互间堆叠的 TextBlock 元素。VisualStateManager 具有在 MinWindowWidth 值为 720 时定义的 AdaptiveTrigger,当窗口宽度至少为 720 个有效像素时,它将使 StackPanel 的方向变为水平。这样的话,当用户在手机或平板电脑设备上调整窗口大小或从纵向模式变为横向模式时,就可以更好地利用额外的横向空间。请记住,如果您同时定义了宽度和高度两个属性,则您的触发器只有在同时满足两个条件的情况下才会被触发。您可以探索 GitHub ([wndw.ms/XUneob](http://wndw.ms/XUneob)) 上的状态触发器示例,查看使用触发器的更多方案,包括许多自定义触发器的示例。
相对面板在图 1 示例中,StateTrigger 用于改变 StackPanel 的 Orientation 属性。XAML 中的许多容器元素与 StateTriggers 相结合,使您能够采用多种方法来控制您的 UI,但却没办法通过它们轻松创建一个元素布置位置彼此相关的复杂且反应灵敏的 UI。这也正是新的 RelativePanel 派上用场的原因。如图 2 所示,您可以通过表达元素间的空间关系,来使用 RelativePanel 布置您的元素。这意味着,您可以轻松使用 RelativePanel 和 AdaptiveTriggers 来创建响应式 UI,您可在其中根据可用的屏幕空间对元素进行移动。
图 2 使用 RelativePanel 表达空间关系
~~~
<RelativePanel BorderBrush="Gray" BorderThickness="10">
<Rectangle x:Name="RedRect" Fill="Red" MinHeight="100" MinWidth="100"/>
<Rectangle x:Name="BlueRect" Fill="Blue" MinHeight="100" MinWidth="100"
RelativePanel.RightOf="RedRect" />
<!-- Width is not set on the green and yellow rectangles.
It's determined by the RelativePanel properties. -->
<Rectangle x:Name="GreenRect" Fill="Green"
MinHeight="100" Margin="0,5,0,0"
RelativePanel.Below="RedRect"
RelativePanel.AlignLeftWith="RedRect"
RelativePanel.AlignRightWith="BlueRect"/>
<Rectangle Fill="Yellow" MinHeight="100"
RelativePanel.Below="GreenRect"
RelativePanel.AlignLeftWith="BlueRect"
RelativePanel.AlignRightWithPanel="True"/>
</RelativePanel>
~~~
需要提醒的是,您使用的带有附加属性的语法中包含了额外的括号,如图所示:
~~~
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState>
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="720" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="GreenRect.(RelativePanel.RightOf)"
Value="BlueRect" />
</VisualState.Setters>
</VisualState>
~~~
您可以在 GitHub ([wndw.ms/cbdL0q](http://wndw.ms/cbdL0q)) 上的响应技术示例中查看其他一些使用 RelativePanel 的方案。
SplitView 应用窗口大小对应用页面的影响不仅仅是对其显示内容的影响;它可能需要导航元素响应窗口本身的大小变化。Windows 10 中引入的新 SplitView 控件通常用于创建顶级导航体验 - 可以根据应用的窗口大小相应地对行为方式进行调整。请记住,虽然这是 SplitView 的常见用例之一,但却不仅限于此用法。将 SplitView 分为两个区域:窗格和内容。
控件上的一些属性可以用来操控呈现。首先,DisplayMode 指定有关内容区域的窗格的呈现方式。有四种可用模式:Overlay、Inline、CompactOverlay 和 CompactInline。图 3 显示了在应用中呈现的 Inline、Overlay 和 CompactInline 模式的示例。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-08_568f407115eaf.png)
图 3 DisplayMode 导航元素
PanePlacement 属性将窗格显示在内容区域的左侧(默认)或右侧。OpenPaneLength 属性指定窗格完全展开时的宽度(默认为 320 个有效像素)。
请注意,SplitView 控件不包括用户用以触发面板状态的内置 UI 元素,如经常出现在移动应用中的“汉堡”菜单。如果您想展示这一行为,则必须在您的应用中定义此 UI 元素,并提供触发 SplitView 的 IsPaneOpen 属性的代码。
是否想探索 SplitView 提供的所有功能? 务必查看 GitHub ([wndw.ms/qAUVr9](http://wndw.ms/qAUVr9)) 上的 XAML 导航菜单示例。
## 引入后退按钮
如果您开发适用于 Windows Phone 早期版本的应用,您可能会习惯于在每台设备上设有一个硬件或软件后退按钮,让用户在您的应用中可以以后退的方式导航。然而,对于 Windows 8 和 8.1,您必须创建您自己的能够实现后退导航的 UI。如果针对的是 Windows 10 应用中的多个设备系列,为了实现起来更加容易,有一种方式可以确保为所有用户提供一致的后退导航机制。这有助于在您的应用运行过程中释放一些 UI 空间。
若要为您的应用启用系统后退按钮,可以使用 SystemNavigationManager 类中的 AppViewBackButtonVisibility 属性,即使是在没有硬件或软件后退按钮的设备系列上(如笔记本电脑和台式电脑)也是如此。只需将 SystemNavigationManager 用于当前视图,并将后退按钮设置为可见,如以下代码所示:
~~~
SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility =
AppViewBackButtonVisibility.Visible;
~~~
SystemNavigationManager 类还展示了一个 BackRequested 事件,当用户调用系统提供的用于后退导航的按钮、手势或语音命令时,该事件就会被触发。这意味着,您可以处理这个单一事件,从而能够在所有设备系列上一致地在您的应用中执行后退导航。
## Continuum 的优点
最后,但并非最不重要的是,我们要提到我们的一个个人收藏夹,供您参考: Windows 10 上的 Continuum。使用 Continuum,Windows 10 可以根据您想要执行的事项和执行的方式调整您的体验。例如,如果您的应用运行在一个二合一的 Windows 电脑上,则在您的应用中实施 Continuum 可以让用户通过触摸或使用鼠标和键盘来优化生产力。通过使用 UIViewSettings 类中的 UserInteractionMode 属性,您的应用仅需借助一行代码即可确定用户是通过触摸与视图实现交互还是通过使用鼠标和键盘实现:
~~~
UIViewSettings.GetForCurrentView().UserInteractionMode;
// Returns UserInteractionMode.Mouse or UserInteractionMode.Touch
~~~
在检测了交互模式之后,您可以优化应用的 UI,比如增加或减少边距、显示或隐藏复杂的功能等等。请查看 Lee McPherson 的 TechNet 文章“Windows 10 Apps: Leverage Continuum Feature to Change UI for Mouse/Keyboard Users Using Custom StateTrigger”(Windows 10 应用:利用 Continuum 功能为使用自定义 StateTrigger 的鼠标/键盘用户更改 UI)([wndw.ms/y3gB0J](http://wndw.ms/y3gB0J)),此文章说明如何结合使用新的 StateTriggers 和 UserInteractionMode 构建您自己的自定义 Continuum StateTrigger。
## 自适应应用
能够响应屏幕尺寸和方向变化的应用是很有用的,但为了实现受人关注的跨平台功能,UWP 为开发人员提供了另外两种类型的自适应行为:
* 通过检测可用的 API 和资源,使自适应应用的版本响应不同版本的 UWP。例如,在继续支持尚未升级的客户的同时,您可能想让您的应用使用一些较新的 API,而这些 API 仅存在于运行最新版本 UWP 的设备上。
* 平台自适应应用可以对不同设备系列提供的独特功能做出响应。因此,可以构建出可在所有设备系列上运行的应用,但当它在智能手机之类的移动设备上运行时,您可能想要使用一些特定于移动的 API。
如前所述,在使用 Windows 10 的情况下,绝大多数 UWP API 都完全可供任何应用使用,无论这些应用在什么样的设备上运行。并且,与每个设备系列相关的特定 API 使开发人员可以进一步调整他们的应用。
自适应应用的基本思维模式是,您的应用会检查它所需要的功能(或特性),并且只在该功能可用的情况下才使用。在过去,应用会检查 OS 版本,然后再调用与该版本相关的 API。有了 Windows 10,您的应用就可以在运行时检查某个类、方法、属性、事件或 API 协定是否受当前操作系统的支持。如果支持,该应用将调用相应的 API。位于 Windows.Foundation.Metadata 命名空间中的 ApiInformation 类包含一些静态方法(如 IsApiContractPresent、IsEventPresent 和IsMethodPresent),它们可用于查询 API。例如:
~~~
using Windows.Foundation.Metadata;
if(ApiInformation.IsTypePresent("Windows.Media.Playlists.Playlist"))
{
await myAwesomePlaylist.SaveAsAsync( ... );
}
~~~
此代码有两个作用。对是否存在 Playlist 类进行运行时检查,然后在该类的一个实例调用 SaveAsAsync 方法。还要注意的是,通过使用 IsTypePresent API,可以轻松检查当前操作系统上是否存在某个类型。在过去,这样的检查可能需要使用 LoadLibrary、GetProcAddress、QueryInterface、Reflection,或使用“动态”关键字等,具体取决于语言和框架。在进行方法调用时,还要注意强类型引用。当使用任何 Reflection 或“动态”时,您无法使用静态编译时诊断,该诊断可能会告知您是否拼错了方法名等。
## 使用 API 协定进行检测
API 协定本质上是一个 API 集。假设 API 协定可代表一个 API 集,其中包含两个类、五个接口、一个结构、两个枚举等。我们将逻辑相关类型编组到一个 API 协定中。在许多方面,一个 API 协定代表一个功能 - 一个相关的 API 集可以一起提供某些特殊功能。Windows 10 往前的每个 Windows 运行时 API 都是某个 API 协定的成员。[msdn.com/dn706135](http://msdn.com/dn706135) 上的文档介绍各种可用的 API 协定。您会看到,它们大多表示一组功能相关的 API。
使用 API 协定还为像您一样的开发人员提供一些其他保障;最为重要的是,当平台可实现某个 API 协定中的任一 API 时,该平台一定可以实现该协定中的每个 API。换句话说,一个 API 协定就是一个原子单元,测试是否支持该 API 协定就相当于测试是否支持该集中的每一个 API。您的应用可以调用已检测的 API 协定中的任何 API,而不必逐个检查每个 API。
最大和最常用的 API 协定是 Windows.Foundation.UniversalApiContract。它包含了通用 Windows 平台中几乎所有的 API。如果您想查看当前 OS 是否支持 UniversalApiContract,您可以编写以下代码:
~~~
if (ApiInformation.IsApiContractPresent(
"Windows.Foundation.UniversalApiContract"), 1, 0)
{
// All APIs in the UniversalApiContract version 1.0 are available for use
}
~~~
目前 UniversalApiContract 唯一现存的版本是 1.0 版,因此该检查略显多此一举。但 Windows 10 的未来更新版本中可能会引入其他 API,可能出现包括新的通用 API的 UniversalApiContract 2.0 版本。在将来,如果某个应用希望能在所有设备上运行,并且还希望使用新的 2.0 版本的 API,可以使用以下代码:
~~~
if (ApiInformation.IsApiContractPresent(
"Windows.Foundation.UniversalApiContract"), 2, 0)
{
// This device supports all APIs in UniversalApiContract version 2.0
}
~~~
如果您的应用只需要从 2.0 版本调用单个方法,可以直接使用 IsMethodPresent 来检查此方法。在这种情况下,您可以使用您认为是最简单的任何方法。
除了 UniversalApiContract 之外,还有其他的 API 协定。大多数表示一个功能或一个 API 集:不是普遍存在于所有 Windows 10 平台上,而是存在于一个或多个特定设备系列上。正如前面所提到的,您不再需要检查设备的特定类型,然后推断是否支持 API。只需检查您的应用要使用的 API 集。
现在我可以重写我原来的示例,用以检查是否存在 Windows.Media.Playlists.PlaylistsContract,而不是仅仅检查是否存在 Playlist 类:
~~~
if(ApiInformation.IsApiContractPresent(
"Windows.Media.Playlists.PlaylistsContract"), 1, 0)
{
// Now I can use all Playlist APIs
}
~~~
无论您的应用何时需要调用所有设备系列中并不存在的 API,您都必须添加一个对定义该 API 的相应扩展 SDK 的引用。在 Visual Studio 2015 中,前往“添加引用”对话框,然后打开“扩展”选项卡。在那里,您可以找到三个最重要的扩展: 移动扩展、桌面扩展以及 IoT 扩展。
但是,您的应用需要做的只是,检查所需 API 协定是否存在,并有条件地调用相应的 API。没有必要担心设备的类型。现在的问题是: 我需要调用 Playlist API,但它不是一个普遍可用的 API。文档 ([bit.ly/1QkYqky](http://bit.ly/1QkYqky)) 会告诉我此类在哪个 API 协定中。但哪个扩展 SDK 会定义它呢?
事实证明,Playlist 类(目前)仅在桌面设备上可用,而不适用于移动设备、Xbox 和其他设备系列。所以,您必须在任何原有代码进行编译之前将引用添加到桌面扩展 SDK 中。
Lucian Wischik 是 Visual Studio 团队的成员和 MSDN 杂志的偶有撰稿人,他创建了一个可提供帮助的工具。该工具会在调用特定于平台的 API 时分析您的应用代码,验证是否完成了与此相关的自适应检查。如果未完成任何检查,分析器就会发出警告,并提供便捷的“快速修复”项以将正确的检查插入到代码中,只需按下“Ctrl+Dot”或单击灯泡图标即可进行。(请参阅 [bit.ly/1JdXTeV](http://bit.ly/1JdXTeV),以了解详细信息。) 分析器也可以通过 NuGet ([bit.ly/1KU9ozj](http://bit.ly/1KU9ozj)) 进行安装。
我们来通过查看有关 Windows 10 自适应编码的更完整示例进行总结。首先,以下是一些未正确自适应的代码:
~~~
// This code will crash if called from IoT or Mobile
async private Task CreatePlaylist()
{
StorageFolder storageFolder = KnownFolders.MusicLibrary;
StorageFile pureRockFile = await storageFolder.CreateFileAsync("myJam.mp3");
Windows.Media.Playlists.Playlist myAwesomePlaylist =
new Windows.Media.Playlists.Playlist();
myAwesomePlaylist.Files.Add(pureRockFile);
// Code will crash here as this is a Desktop-only call
await myAwesomePlaylist.SaveAsAsync(KnownFolders.MusicLibrary,
"My Awesome Playlist", NameCollisionOption.ReplaceExisting);
}
~~~
现在,我们来看同样的代码,我们添加一行用来验证目标设备上是否支持可选 API 的代码行,然后再调用方法。这样做可以防止发生运行时故障。请注意,您可能想进一步利用这个示例,在您的应用检测到设备上不支持播放列表功能时,不显示调用 CreatePlaylist 方法的 UI:
~~~
async private Task CreatePlaylist()
{
StorageFolder storageFolder = KnownFolders.MusicLibrary;
StorageFile pureRockFile = await storageFolder.CreateFileAsync("myJam.mp3");
Windows.Media.Playlists.Playlist myAwesomePlaylist =
new Windows.Media.Playlists.Playlist();
myAwesomePlaylist.Files.Add(pureRockFile);
// Now I'm a safe call! Cache this value if this will be queried a lot
if (Windows.Foundation.Metadata.ApiInformation.IsTypePresent(
"Windows.Media.Playlists.Playlist"))
{
await myAwesomePlaylist.SaveAsAsync(
KnownFolders.MusicLibrary, "My Awesome Playlist",
NameCollisionOption.ReplaceExisting);
}
}
~~~
最后,以下是一个代码示例,看上去可以访问许多移动设备上显示的专用照相机按钮:
~~~
// Note: Cache the value instead of querying it more than once
bool isHardwareButtonsAPIPresent =
Windows.Foundation.Metadata.ApiInformation.IsTypePresent(
"Windows.Phone.UI.Input.HardwareButtons");
if (isHardwareButtonsAPIPresent)
{
Windows.Phone.UI.Input.HardwareButtons.CameraPressed +=
HardwareButtons_CameraPressed;
}
~~~
请注意检测步骤。如果我在使用台式电脑时,对 CameraPressed 事件直接引用了 HardwareButtons 对象,而没有检查 HardwareButtons 是否存在,这可能会导致我的应用发生故障。
还有许多关于 Windows 10 中响应式 UI 和自适应应用的内容。您是否想了解更多? 请查看在 Build 2015 会议 ([wndw.ms/IgNy0I](http://wndw.ms/IgNy0I)) 上 Brent Rector 做出的有关 API 协定的精彩演讲,并且务必要观看内容详尽的有关自适应代码的 Microsoft Virtual Academy 视频 ([bit.ly/1OhZWGs](http://bit.ly/1OhZWGs)),视频中涵盖了本主题的更多详细信息。
* * *
Clint Rutkas *是一位专注于开发人员平台的 Windows 资深产品经理。他在 Microsoft 的“Halo at 343 Industries”和第 9 频道从事工作,并构建出一些使用 Windows 技术的疯狂项目,如计算机控制的迪斯科舞池、一个自定义的 Ford Mustang、T 恤射击机器人等。*
Rajen Kishna *目前在华盛顿雷德蒙德担任 Microsoft 的 Windows 平台开发人员市场营销团队的资深产品营销经理。此前,他在荷兰担任 Microsoft 的顾问和技术推广员。*
UI 设计 – 通用 Windows 应用的响应式设计
最后更新于:2022-04-01 06:55:44
WINDOWS 10 2015 年特别版
# UI 设计 - 通用 Windows 应用的响应式设计
作者 [Mike Jacobs](https://msdn.microsoft.com/zh-cn/magazine/mt149362?author=Mike+Jacobs) | Windows 2015
通用 Windows 应用可以在任何基于 Windows 的设备(包括从手机到平板电脑或电脑)上运行。您甚至可以创建在紧凑型设备(如便携式设备或家用电器)上运行的通用 Windows 应用。您可以将您的应用限定用于单一的设备系列(如移动设备系列),也可以选择使应用可在所有运行 Windows 的设备上使用。
将一个应用设计为可在各种各样的设备上使用似乎是一个很好的想法,但却是一项很大的挑战。那么,您会如何针对屏幕尺寸和输入法差别迥异的设备设计一款能够提供完美 UX 的应用呢? 所幸的是,通用 Windows 平台 (UWP) 提供了一套内置功能和通用构建基块,可以帮助您做到这一点。本文介绍了 UWP 的设计功能,并提供了一些关于创建可适应于不同设备和外形规格的响应式 UI 的建议。
当您创建通用 Windows 应用时,我们首先来考虑一些您可以使用的功能。您不必做任何事情便可使用这些功能 - 它们已包含在 UWP 之中。
其中一个功能是平台缩放功能,可根据使用的 Windows 驱动的设备类型对 UI 进行优化。该系统使用一种算法来标准化控件、字体和其他 UI 元素在屏幕上的显示方式。这个缩放算法考虑了观看距离和屏幕密度(每英寸像素),以对感知大小(而不是物理大小)进行优化。缩放算法保证了在 10 英尺远的 Surface Hub 显示装置上显示的 24 像素字体与用户在几英寸远的 5 英寸智能手机屏幕上显示的 24 像素字体一样清晰。鉴于缩放系统的这种工作模式,当您设计通用 Windows 应用时,您要使用有效像素进行设计,而不要使用实际的物理像素进行设计。
UWP 的另一个内置功能是通过智能交互启用的通用输入功能。虽然您可以针对特定的输入模式和设备来设计您的应用,但这不是必要的。这是因为通用 Windows 应用在默认情况下依靠智能交互。这意味着,您可以围绕着单击交互进行设计,而不必知道或定义该单击是源于实际的鼠标单击还是源于手指的点按操作。
## 通用构建基块
此外,UWP 提供了有用的构建基块,可以更容易地设计出适用于多个设备系列的应用。这些构建基块包括通用控件、通用样式和通用模板。
可以保证通用控件在所有以 Windows 为基础的设备(从智能手机到 Surface Hub 显示器)上正常工作。它们运行的域范围从单选按钮和文本框这类常见的窗体控件到网格视图和列表视图这类复杂的控件(可以从数据流和模板中生成项目列表)。这些控件具有输入感知的特点,可针对每个设备系列部署一组适当的输入提示、活动状态和整体功能。
UWP 还会自动为您的应用套用一组默认的样式,该组样式会针对每个目标外形规格优化呈现方式。您可以自定义默认样式或彻底进行替换,以创建独特的视觉体验。通用样式提供了许多功能,包括:
* 一组样式,它可以自动为您的应用选择浅色或深色主题并可结合用户的色彩偏好
* 一种基于 Segoe 的类型校正,它确保该应用文本可在所有设备上呈现出清晰效果
* 默认的交互动画
* 自动支持高对比度模式。这些样式都特意采用高对比度设计,因此,当应用采用高对比度模式在设备上运行时,可正确进行显示
* 自动支持其他语言。默认样式为 Windows 支持的每一种语言自动选择正确的字体。您甚至可以在相同的应用中使用多种语言,并正确显示这些语言
* 内置支持从右到左的阅读顺序
最后,UWP 提供了适用于 Adobe Illustrator 和 Microsoft PowerPoint 的通用模板,并包含您开始设计 UWP 应用所需的一切。这些模板具有适用于每个通用设备尺寸类的通用控件和布局。若要下载模板,请转到 Windows 开发人员中心 [bit.ly/1KHun6J](http://bit.ly/1KHun6J) 的设计下载部分。
## 了解设备
为了在您的应用中尽可能提供最佳的 UX,熟悉 UWP 支持的各种设备系列非常重要。当设计用于特定设备时,主要考虑的因素包括:在该设备上应用如何显示,用户以何种方式与该设备进行交互,以及在该设备上应在何处、何时和如何使用该应用。
智能手机 是所有计算设备中最广泛使用的;手机可以在有限的屏幕空间和基本的输入模式下实现很多用途。手机有各种尺寸,大多数对角线长度范围在 4 至 6 英寸之间,而屏幕大于 6 英寸的手机通常被称为平板手机。虽然,在平板手机上的应用体验与在标准大小的智能手机上的体验非常相似,但大屏幕可以支持内容使用方面的某些重要变化。
手机主要在纵向上使用,这主要是为了在交互过程中易于用一只手拿着手机。横向上的良好体验则包括观看照片和视频、阅读书籍以及撰写文本。无论大小和使用模式如何,手机都具有某些相同特点。它们大多只供一个人(即设备的所有者)使用,并且往往是触手可及,通常放在口袋或提包中。手机的使用时间通常较短。
用户通过触摸和语音与自己的手机交互。大多数手机提供照相机、麦克风、移动传感器和位置传感器功能。
平板电脑 超便携式平板电脑填补了手机和笔记本电脑之间的空隙。常备触摸屏、照相机、麦克风和加速计的平板电脑的屏幕大小范围通常为 7 至 13 英寸左右。像手机一样,平板电脑也主要由一个人(它的所有者)使用。它们常在家中使用,使用时间比手机长。用户通过触摸、触笔,有时是键盘和鼠标,与平板电脑交互。
电脑和笔记本电脑 Windows 电脑包括各种大小的设备和屏幕尺寸。在一般情况下,电脑和笔记本电脑可以显示比手机或平板电脑更详细的信息。典型屏幕尺寸为 13 英寸或以上。电脑和笔记本电脑上的应用可共享使用,但一次可供一个用户使用,通常使用时间较长。应用可以显示在一个窗口视图中,它的大小由用户确定。电脑和笔记本电脑的用户主要使用鼠标和键盘与应用交互,但许多笔记本电脑和一些电脑也支持触摸交互。电脑和台式机通常不会像其他设备那样有非常多的内置传感器,而且大部分仅配备一个照相机和一个麦克风。
Surface Hub 设备 Microsoft Surface Hub 是专为多个用户同时使用而设计的大屏幕团队协作设备。Surface Hub 的可用屏幕尺寸范围为 55 到 84 英寸之间。Surface Hub 上的应用可在短时间内共享使用,例如在会议中使用,并且可以四种状态进行显示:填充(一个占据可用场景区域的固定视图)、全屏(标准全屏视图)、辅屏(一个占据场景的右侧或左侧的可变视图)和背景(当应用仍在运行时,可通过任务切换器实现隐藏的效果)。Surface Hub 支持触摸、触笔、语音和键盘交互,并且包括照相机和麦克风。
Windows 物联网设备 这一新兴类以实物中嵌入的小电子产品、传感器和连接性为中心。这些设备通常通过网络或 Internet 实现互联,并提供它们感测到的现实世界数据的报告,并且在某些情况下采取相应操作。设备可以没有屏幕(“无外设”设备),或可以连接到一个 3.5 英寸或更小的小屏幕(“有外设”设备)上。输入和设备功能因设备的不同而千差万别。
## 设计特定设备
由于 Windows 在后台工作以确保您的 UI 清晰可辨并能跨所有设备正常运转,所以您不必针对任何特定的设备或屏幕尺寸自定义您的应用。然而,有些时候您可能想要这样做。例如,当您的应用运行在电脑或笔记本电脑上时,您要显示的其他内容可能会打乱像手机这样较小设备的屏幕。
有许多方法可以提高您的应用适应特定屏幕尺寸的功能;其中有一些既快速又简单,而有些则需要做一些努力工作。
我们先再谈些关于有效像素的内容。正如之前所述,当您设计通用 Windows 应用时,您要使用有效像素进行设计,而不要使用实际的物理像素进行设计。有效像素使您能够专注于 UI 元素的实际感知大小,而不必担心不同设备的像素密度或观看距离。例如,当您设计一个 1 英寸 × 1 英寸的元素时,该元素将在所有设备上显示为大约 1 英寸大小。在具有高像素密度的非常大的屏幕上,该元素可能是 200 × 200 个物理像素大小,而在像手机这种较小设备上,它可能是 150 × 150 个物理像素大小。
那么,这会对您设计应用的方式产生怎样的影响呢? 设计时可以忽略像素密度和实际的屏幕分辨率。相反,需要为尺寸类设计有效分辨率(有效像素的分辨率)。稍后,我将在本文中详细介绍尺寸类分辨率。此外,有一个快速提示: 当在图像编辑程序中创建屏幕模型时,请务必将 PPI 设置为 72,将图像尺寸设置为您针对的尺寸类的有效分辨率。
为确保您的应用可彻底实现缩放,服从四个规则很重要: 通过使用 UI 元素的边距、尺寸、位置(包括文本位置)构成四个有效像素的倍数关系,将您的设计对齐 4×4 像素网格。图 1 显示映射到 4×4 像素网格的设计元素。该设计元素将始终有清晰醒目的边缘。相反,设计的元素如果映射不到 4x4 网格,在一些设备上将呈现出模糊和柔化边缘的效果。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-08_568f40709bd94.png)
图 1 对齐到 4×4 像素网格可呈现清晰的文本和图像
尽管有这些资源和功能,但有时候您可能想为特定的设备系列自定义您的应用的 UI。例如,您可能需要尽可能最有效地利用空间,减少用户的导航负担。将应用设计成在手机等小屏幕设备上具有出色的观看效果,对于具有大尺寸显示器的电脑而言是有用的,但也有可能浪费一些空间。您可以将应用自定义为在屏幕大于特定尺寸时可以显示更多的内容。例如,购物应用在手机上可能一次只显示一个商品类别,但在电脑或笔记本电脑上可同时显示多个类别和产品。通过将更多的内容放在屏幕上,可以减少用户需要执行导航的工作量。
其他可以想到的场景,例如您需要充分使用设备的功能时。例如,手机可能有位置传感器和照相机,而电脑可能什么都没有。您的应用可以检测到哪些功能是可用的,然后启用使用它们的功能。
最后,您可能想要优化输入。通用控件库可与所有输入类型(触摸、触笔、键盘和鼠标)配合使用,但是您仍然可以通过重新安排 UI 元素对特定的输入类型进行优化。例如,如果将导航元素放置在屏幕底部,便可以让手机用户更轻松地进行访问,但大多数电脑用户却希望在屏幕顶部看到导航元素。
## 响应式设计技术
当为特定的屏幕宽度优化您的应用 UI 时,您是在创建一个响应式设计。有很多有用的响应式设计技术可供您用于自定义您的应用 UI,以及充分利用不同设备类型的屏幕空间和可用的功能。有六个技术可供考虑:重新定位、重设大小、重排、显示、替换和重构。
重新定位应用 UI 元素是充分利用每台设备的一种方法。在图 2 中,手机或平板手机的纵向视图需要滚动 UI,因为一次只能看到一个完整的框架。当应用转换到允许使用两个完整屏幕框架的平板电脑或其他设备上时,无论是在纵向或在横向方向,框架 B 都可以转变为占据一个专用空间。如果使用网格进行定位,当重新定位 UI 元素时,您能始终贴紧同一网格。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-08_568f4070cd9c5.png)
图 2 重新定位框架可以充分利用较大的屏幕
也可以通过重设边距和 UI 元素的大小对框架进行优化,以充分利用更小或更大的屏幕。例如,通过扩大内容框,为更多的文本腾出空间和减少滚动量,让您在更大的屏幕上增大阅读体验。同样的道理,不同的框大小可以根据设备和方向提供重排 UI 元素的机会。例如,屏幕较大时,使用较大容器、增加列并以不同于智能手机的方式生成列表项会变得很有意义。
显示 UI 元素是一个功能强大的技术,可以显示在特定设备上受支持的功能(例如,智能手机的照相机功能),同时也提供了一些利用不同屏幕尺寸和方向的选项。显示或隐藏 UI 的常见示例适用于媒体播放器控件,即在较小的设备上按钮集数量减少,而在较大的设备上,按钮集数量增多。例如,比起在手机上,电脑上的媒体播放器可以操作更多的屏幕功能。
显示或隐藏技术的一部分功能包括,选择何时显示更多元数据。当屏幕空间严重不足时,最好的办法是尽量减少显示的元数据数量,而笔记本电脑或台式电脑却允许显示很多元数据。如何处理显示或隐藏元数据的一些示例包括:
* 电子邮件应用:显示用户的头像
* 音乐应用:显示有关专辑或艺术家的更多信息
* 视频应用:显示有关电影或放映的更多信息,如演员表和职员表的详细信息
* 任何应用:中断列并显示更多信息
* 任何应用: 选取垂直堆叠的项目,并将其沿水平方向放置;在较大的设备上,堆叠列表项目可以改为显示列表项目的行和元数据的列
最后两个响应式 UI 技术是替换和重构。替换技术使您可以切换 UI,使其满足特定的设备尺寸类或方向。例如,一个紧凑的设备可能会显示堆叠按钮系列,而在较大屏幕上,那些控件将被替换为运行在屏幕顶部的选项卡。
最终,您可以折叠或拆分应用的架构,以便更好地针对特定的设备。在图 3 的示例中,从左边的设备到右边的设备,演示了页面间的联接。该图像描述了一个智能家庭应用,在较大的屏幕上将家庭控件和设置窗格组合在单个的屏幕上。在较小的设备上,控件和设置显示在不同的屏幕上。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-08_568f4070eddbf.png)
图 3 为不同的屏幕尺寸重构应用显示
## 设计断点
Windows 10 生态系统中的设备目标和屏幕尺寸繁多,您无需为逐一优化您的 UI 而有所顾虑。相反地,建议您设计三个关键值宽度(也称为断点): 320、720 和 1024 个有效像素。图 4 描述断点。
图 4 设计响应式 UI 的断点
| 尺寸类 | 小型 | 中型 | 大型 |
|--------|--------|--------|
| 有效像素宽度 | 320 | 720 | 1024 |
| 典型屏幕尺寸(对角线) | 4 英寸到 6 英寸 | 6 英寸以上到 12 英寸 | 13 英寸或更宽 |
| 典型设备 | 手机 | 平板电脑、具有较大屏幕的手机 | 电脑、便携式计算机、Surface Hub |
当设计特定的断点时,要考虑您的应用(或应用窗口)可用的屏幕空间。当应用全屏运行时,应用窗口与屏幕大小相同,但在其他情况下,应用窗口更小。
当设计小型 UI 时,每一个像素都是很宝贵的,因此可以隐藏主场景的非必需功能,可以将这样的功能放在菜单或工具栏中。一次显示一列内容或一个内容区域,并用一个图标来表示搜索,而不是显示一个搜索框,这样做也是一个很好的主意。
上移至中型尺寸的 UI,您可以利用额外的空间显示搜索框(如果有的话),并将主内容置于两列或两个区域中。如果上升至大型 UI,将能够显示更多的功能和内容,并可以减少获取内容或执行操作所需的单击和 UI 交互数量。
请记住,320 个有效像素的宽度可能意味着您的应用正运行在手机上或运行在大屏幕电脑上的一个小窗口中,所以务必要考虑设备的主要输入方式 - 鼠标或触摸。在触摸设备上,将导航和命令元素放在屏幕底部拇指容易碰触的地方,可以更轻松在手持设备上进行导航和交互。但是,当使用鼠标时,用户希望导航元素出现在屏幕的顶部。您的应用可以使用 Windows.UI.ViewManagement.UIViewSettings.UserInteractionMode 属性来找到主要的输入设备,并相应地调整其 UI。
通用 Windows 平台可以让您的应用在以下范围的设备中打开:从使用小屏幕的便携式设备到巨大的 Surface Hub。通过实施响应式设计技术和利用该平台的内置功能和构建基块(控件和样式),可以创建一个在所有尺寸和形状的设备上看起来都很棒的 UI。
* * *
Mike Jacobs *是 Microsoft 的一名高级内容开发人员。多年来,他一直在记录 Microsoft 技术(从 Direct2D 到 Windows Presentation Foundation 和 Silverlight)的图形和呈现方面的内容。*
Visual Studio 工具 – NuGet 功能增强了 Windows 10 的开发功能
最后更新于:2022-04-01 06:55:42
WINDOWS 10 2015 年特别版
# Visual Studio 工具 - NuGet 功能增强了 Windows 10 的开发功能
作者 [Jeff Fitz](https://msdn.microsoft.com/zh-cn/magazine/mt149362?author=Jeff+Fitz) | Windows 2015
现在 NuGet 团队提供了几款全新工具。它与 Microsoft 的一些团队合作推出了新版本的 NuGet 客户端,以支持通用 Windows 平台 (UWP) 和新的可移植类库 (PCL)。新的 NuGet 工具可通过“工具 | 扩展和更新 | Visual Studio 2015 中的更新”获取,还可以从 NuGet 分布站点获取,网址为:[bit.ly/1MgNt2J](http://bit.ly/1MgNt2J)。NuGet 还发布了新版本的 NuGet 命令行工具,您可以从 dist.nuget.org 上的相同位置下载它。本文将回顾这些新功能和 Windows 开发者向 Windows 10 项目添加 NuGet 支持需要遵循的进程。
## Project.Json
从 ASP.NET 5 开始,NuGet 引入了 project.json 文件支持,以便使用您会立即依赖的程序包的明确定义来描述项目依赖项。在 ASP.NET 5 中,这是定义项目配置的唯一文件。但是借助 NuGet 3.1,您可以在通用 Windows 项目和现代 PCL(面向 DNX、UWP 和 Microsoft .NET Framework 4.6)中使用此文件来定义程序包引用。这种方法的好处就是 Visual Studio 中的“管理程序包”对话框将基于您所开发的项目类型,适当维护您的 packages.config 或 project.json 文件。
这一转变从 packages.config 模型开始,还允许您“重启”项目中的引用,并使用 NuGet 的新的可传递依赖项功能。开发者和程序包作者向 NuGet 团队报告,当他们将程序包添加到项目时,他们的 packages.config 文件会与其依赖程序包中的依赖项混淆。
例如,NHibernate 是依赖于 Iesi.Collections 程序包的程序包。在 packages.config 中有两个引用:NHibernate 和 Iesi.Collections。在更新 NHibernate 时,会遇到一个问题“我是否也要更新 Iesi.Collections?” 同样存在与此相反的问题。如果有适用于 Iesi.Collections 的更新,我是否需要更新 NHibernate 来支持 Iesi.Collections 中的新功能? 开发者可能会陷入对程序包引用所带来的项目程序包依赖项进行管理的令人厌恶的循环。
NuGet 的可传递依赖项功能简化了这一决定,通过程序包定义文件(nuspec 文档)中语义版本的改进支持更新程序包引用。开发者指定了其程序包支持的依赖项版本范围。当 NuGet 安装客户端时,这些依赖项会对 packages.config 文件中的指定版本添加硬引用,这些引用的程序包看上去就像您添加到项目中的任何其他程序包引用。您可以在图 1 中看到这一问题的极好示例。
图 1 ASP.NET MVC packages.config 文件的内容
~~~
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Antlr" version="3.4.1.9004" targetFramework="net46" />
<package id="bootstrap" version="3.0.0" targetFramework="net46" />
<package id="EntityFramework" version="6.1.3" targetFramework="net46" />
<package id="jQuery" version="1.10.2" targetFramework="net46" />
<package id="jQuery.Validation" version="1.11.1" targetFramework="net46" />
<package id="KendoUICore" version="2015.2.624" targetFramework="net46" />
<package id="Microsoft.AspNet.Identity.Core" version="2.2.1" targetFramework="net46" />
<package id="Microsoft.AspNet.Identity.EntityFramework"
version="2.2.1" targetFramework="net46" />
<package id="Microsoft.AspNet.Identity.Owin" version="2.2.1" targetFramework="net46" />
<package id="Microsoft.AspNet.Mvc" version="5.2.3" targetFramework="net46" />
<package id="Microsoft.AspNet.Razor" version="3.2.3" targetFramework="net46" />
<package id="Microsoft.AspNet.Web.Optimization" version="1.1.3" targetFramework="net46" />
<package id="Microsoft.AspNet.WebPages" version="3.2.3" targetFramework="net46" />
<package id="Microsoft.CodeDom.Providers.DotNetCompilerPlatform"
version="1.0.0" targetFramework="net46" />
<package id="Microsoft.jQuery.Unobtrusive.Validation"
version="3.2.3" targetFramework="net46" />
<package id="Microsoft.Net.Compilers"
version="1.0.0" targetFramework="net46" developmentDependency="true" />
<package id="Microsoft.Owin" version="3.0.1" targetFramework="net46" />
<package id="Microsoft.Owin.Host.SystemWeb" version="3.0.1" targetFramework="net46" />
<package id="Microsoft.Owin.Security" version="3.0.1" targetFramework="net46" />
<package id="Microsoft.Owin.Security.Cookies" version="3.0.1" targetFramework="net46" />
<package id="Microsoft.Owin.Security.Facebook" version="3.0.1" targetFramework="net46" />
<package id="Microsoft.Owin.Security.Google" version="3.0.1" targetFramework="net46" />
<package id="Microsoft.Owin.Security.MicrosoftAccount"
version="3.0.1" targetFramework="net46" />
<package id="Microsoft.Owin.Security.OAuth" version="3.0.1" targetFramework="net46" />
<package id="Microsoft.Owin.Security.Twitter" version="3.0.1" targetFramework="net46" />
<package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net46" />
<package id="Modernizr" version="2.6.2" targetFramework="net46" />
<package id="Newtonsoft.Json" version="6.0.4" targetFramework="net46" />
<package id="Owin" version="1.0" targetFramework="net46" />
<package id="Respond" version="1.2.0" targetFramework="net46" />
<package id="WebGrease" version="1.5.2" targetFramework="net46" />
</packages>
~~~
在我将这些内容添加到项目中时,我实际上只需要 Microsoft.AspNet.Mvc、Microsoft.AspNet.Identity.EntityFramework、Newtonsoft.Json 和 Microsoft.Owin.Security.MicrosoftAccount。这四个程序包所引用的其他项目都只是干扰,现在我有特定版本的硬引用。通过可传递依赖项功能,不再需要其他这些程序包的版本。我只需管理我真正要在项目中使用的四个库。
NuGet 客户端会在后台为您解决和管理其他这些程序包,并将这些引用保持在项目中正在使用的程序包所声明的依赖版本约束范围内。这会极大地简化项目引用体验。
## 常见的本地程序包缓存
开发者通常有自己倾向使用的一些程序包和工具。在您明显已经在某个项目中拥有这些程序包和工具并想在另一个项目中使用时,为什么需要在单个工作站上多次下载并安装它们? 通过 project.json 托管的项目,NuGet 下载这些程序包的副本并将其存储在位于 %userprofile%\.nuget\packages 文件夹的全局程序包文件夹中。这会减少在工作站上使用磁盘空间。还能避免额外调用,这些调用从 NuGet.org 提取程序包来获取您已经拥有的项目。
Project.json 和常见的本地程序包缓存支持可供包含 NuGet 3.0 的 ASP.NET 5 以及其他始于 NuGet 3.1 的项目类型使用。
## 弃用的功能
从 NuGet 3.1 开始,在使用 project.json 时,弃用对执行 install.ps1/uninstall.ps1 脚本和在 /content 程序包文件夹中传递元素的支持。使用这些元素安装程序包既不会执行 install.ps1 文件,也不会将内容复制到您的项目中。但是,在仍使用 packages.config 文件的项目中,仍然支持执行当前行为。出现这一情况有几个原因:
* 随着可传递程序包还原,无法可靠地选取要卸载和安装的程序包。
* 在将内容复制到用户项目,且程序包进行了更新时,会存在您无法可靠运行的隐式卸载过程。
* NuGet 需要完全支持 Visual Studio 之外的开发。随着转向支持完全跨平台 .NET 开发体验,Windows Powershell 在其他环境中不可用。更多的开发者还致力于开发 Visual Studio 之外的 .NET 代码,他们需要支持。
* 其他程序包管理器提供了管理和传递内容的卓越体验。NuGet 可以作为 .NET Framework 的程序包管理器良好地工作,因此,鼓励继续使用。
* 不再支持“任何”框架。您无法再将文件直接放置于版本的根和库文件夹中,并将它们传送给项目。声明您的文件所支持的框架是非常重要的,这样,NuGet 才能了解解析这些引用的优先级顺序。
* 不再支持解决方案包。这些程序包不能修改任何指定项目的功能,通常用于提供跨项目重复使用的共享资源。借助新共享的程序包文件夹,这些资源可能已经位于另一个项目的磁盘上。
## 新目标框架
NuGet 新版本的另一方面是支持新开发框架以及跨操作系统和体系结构的改进的本机程序包支持。NuGet 进一步探索了托管 .NET Framework 模型之外的环境,以支持更多的生态系统,使您可以将库部署到以前无法访问的环境。
目标框架名字对象 (TFM) 是一种简写形式,用于创建程序包来声明二进制支持的框架以及每个框架需要的依赖项。您将在使用此表示法的程序包库和 ref 文件夹中找到文件夹的名称。程序包的 nuspec 依赖项元素中还有一些元素,这些元素使用一个 TFM 值声明目标框架属性来指示 NuGet 客户端将相应的库传递给使用项目。
下列 TFM 仍可用,引入的新 TFM 如图 2 所示。
图 2 NuGet 3.x 支持的目标框架
| 说明 | 基础代码 | 可用版本 |
|---|---|---|
| 托管框架应用程序(Windows 窗体、控制台应用程序、Windows Presentation Foundation 和 ASP.NET) | net | net11、net20、net35、net35-client、net35-full、net4、net40、net40-client、net40-full、net403、net45、net451、net452 和 net46 |
| ASP.NET 5 | dnxcore | dnxcore50 |
| Windows 应用商店 | netcore | win8 = netcore45、win81 = netcore451 和 uap10.0 |
| Windows Phone(appx 模型) | wpa | wpa81 |
| Windows Phone (Silverlight) | wp | wp7 = sl3-wp、wp71 = sl4-wp71、sl4-wp、wp8 = wp8- 和 wp81 |
| Silverlight | sl | sl2、sl3 = sl30、sl4 = sl40 和 sl5 = sl50 |
| Xamarin | | mono、MonoMac、Xamarin.Mac、MonoAndroid10、MonoTouch10 和 Xamarin.iOS10 |
| Compact Framework | net-cf | net20-cf、net35-cf = cf35 和 net40-cf |
| Micro Framework | netmf | netmf41、netmf42 和 netmf43 |
所列出的带有等于 (=) 符号的项是 NuGet 支持的同义词。针对许多不同的框架有许多支持,但这可能会造成混淆。您是否需要为托管框架包中的微框架提供支持? 您需要获得多少 Silverlight 支持? 您需要回答这些问题,以便最符合使用者的需求。
您会发现表中没有支持 PCL 的显式调用。尽管 NuGet 支持这些框架的组合,但它希望您拥有适用于现代 PCL 的更加向前兼容的名字对象。这会在您构造程序包和定义支持框架时提供更多的灵活性。NuGet 3.1 引入了适用于现代 PCL 的 dotnet 目标名字对象。
## Dotnet 目标名字对象
在 NuGet 的早期版本中,您可以指定带有 PCL 的框架,该框架作为后接加号符号的 TFM 缩写的集合。您可能会使用类似“portable-net45+win8+wpa81+wp8”作为文件夹名称的结尾。 这可能会造成混淆,给使用者带来不兼容的问题。为了使 PCL 和跨平台开发体验更加简单,NuGet 引入了 dotnet 名字对象。
此名字对象不会直接与任何指定版本或框架功能绑定。这是一个间接的引用,告诉 NuGet“如果它支持您拥有的框架和运行时功能的话,这是您应该使用的应用。” 然后 NuGet 客户端研究该引用以确定其支持的功能和框架。这一进程会持续,直到 NuGet 客户端解析 dotnet 引用支持的确切功能。然后,只有在引用匹配项目的功能和需求的情况下,客户端才会应用该引用。您可以通过 .NET Framework 4.5 以及后续派生的 Framework 版本(包括 Xamarin Android 和 Xamarin iOS)来引用 dotnet 名字对象。
这并不意味着您只需构建 PCL,并将其与声明的 dotnet 依赖项捆绑在一起,就完成操作了。如果您想要使用旧版本的 Visual Studio 和通过传统可移植类库构建的 NuGet 客户端来支持项目,则应创建一个引用,并将其放置于完整 PCL 目标框架名字对象中。
在将程序包安装到与 dotnet 名字对象(.NET Framework 4.6、UWP 或 ASP.NET 5)完全兼容的项目类型时,最后会搜寻 dotnet 名字对象。在尝试查找与项目的框架或不太具体的框架相匹配的引用后,将会引发上述操作。该层次结构如图 3 所示。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-08_568f40707cbfc.png)
图 3 框架层次结构,检查其中是否存在对通用 Windows 平台项目的引用
如果您的项目是使用仅针对这些框架中的任一个框架的 project.json 的现代 PCL,则会首先分析 dotnet 名字对象。后跟一个标准的 PCL 解决策略,如图 4 所示。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-08_568f40708a717.png)
图 4 框架层次结构,检查其中是否存在对现代可移植类库项目的引用
## NuGet 命令行
现在 NuGet 类似于命令的可执行文件 nuget.exe 可用于支持将程序包安装、更新和还原到包含 packages.config 文件或 project.json 文件的项目。pack 命令可以继续使用磁盘上的 nuspec 文件和 packages.config 文件。它并没有更新为基于 project.json 文件生成 nuspec 文件。要解决此问题,您需要针对任何通过 project.json 程序包引用构造的新程序包内容构建您自己的 nuspec 文件。未来版本中将包含解决此问题的更新。
此版本的命令行可执行文件还支持 NuGet.org v3 终结点。此 nuget.org 源的新版本提供更快的交互,同时也是更加可靠的服务。通过内置的冗余和内容传送网络可以帮助快速传递程序包。从以下网址下载更新 NuGet.exe 的副本:[bit.ly/1UV0kcU](http://bit.ly/1UV0kcU)。
如果您在升级 NuGet 扩展后安装了 Windows 10 SDK/Windows 10 工具,则安装程序会将此扩展降级为版本 3.1。您需要重新将其至少更新为 3.1.1 版本。在此“扩展和更新”对话框中显示的版本是 3.1.60724.766。Windows PowerShell 控制台是 3.1.1.0。
## 总结
现已提供支持 Windows 10 UWP 应用程序开发和 PCL 项目的功能。这些更改是广泛使用程序包管理器和 .NET Framework 的第一步。Microsoft 持续改进 .NET 开发体验,并专注于提供程序包管理器,以支持所有 .NET 开发者在任何平台上构建任何类型的项目。
* * *
Jeffrey T. Fritz *是就职于 Microsoft NuGet 团队的高级项目经理。他喜欢长时间地在海滩上散步,并处理在云中缩放的 Web 应用程序。您可以通过 [jefritz@microsoft.com](mailto:jefritz@microsoft.com) 与他联系。*
应用集成 – 在 Windows 10 上链接和集成应用
最后更新于:2022-04-01 06:55:39
WINDOWS 10 2015 年特别版
此文章由机器翻译。
# 应用集成 - 在 Windows 10 上链接和集成应用
通过 [Arunjeet Singh](https://msdn.microsoft.com/zh-cn/magazine/mt149362?author=Arunjeet+Singh) |Windows 2015 年
大多数应用程序开发人员生成或定期维护多个应用程序。如成熟应用程序,用户经常要求涉及协同工作的多个应用程序的工作流。例如,您可能有的应用程序管理产品库存和未签出的另一个应用程序。理想的做法是为协同工作以完成采购工作流的两个应用程序。
若要解决这一难题的一种方法是只需将所有功能都合并到一个应用程序。实际上,这是一种方法通常在桌面类应用程序中看到。但是,这是充满了危险性的道路。很快,您得到的大多数用户只能使用功能的特定子集的臃肿应用程序。应用程序开发人员现在必须管理 UI 复杂性和整个应用程序的更新。甚至更糟糕,作为 UI 复杂性的增加,用户 — 尤其是在移动 — 开始倾向于多个主要选项。实际上,这种趋势已向以便用户可以安装和使用他们的需要在路上而无需担心他们并不需要的多余的位将应用程序分解到各自经验。
若要解决此问题的第二种方法是通信的利用云作为一种应用程序之间。直到获得超过某个大小或您的数据量非常适用于运行到用户通过有限的连接。这将启动以显示与抱怨如、",在这里我状态之间进行更新,但它不会显示在此其他应用程序那边!" 此外,我总是发现它有点奇怪该应用程序开发人员必须求助于云坐在同一个设备上的两个应用程序之间进行通信。必须有一种更好的方法。
在本文中,我将介绍一些 Windows 10 为了使应用程序更容易之间的通信而提供的工具。应用程序之间的通信可以采用以下形式的应用程序启动另一个应用程序与一些数据,也可能表示应用程序只需交换与每个其他而无需任何操作启动的数据。Windows 10 提供了可用于这两种情况的工具。
## 准备应用程序的深层链接
让我们来举的产品库存应用程序可以显示有关产品的详细信息的示例。现在,我们还将向可以显示各种趋势有关什么在哪个位置销售和销售需要去哪里何种混合的销售应用程序。销售应用程序具有较允许用户查看有关各个产品的详细信息的向下钻取的用户体验。当然,产品的最详细的视图是在库存应用程序中。图 1 显示举例说明了有关哪些我所讨论的方案。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-08_568f40703a932.png)
图 1 销售应用程序清单应用程序的深层链接
在此方案中,您需要执行的第一件事就是使清单应用程序可用于启动。若要执行此操作将添加到清单应用程序的包清单 (package.appxmanifest) 的协议声明。协议声明是告诉它是可由其他应用程序启动世界库存应用程序的方法。图 2 显示此声明如下所示。请注意我使用的协议名称 com.contoso.showproduct。这是有效的命名约定为自定义协议,因为 Contoso 拥有域 contoso.com。其他应用程序开发人员错误地使用相同的自定义方案所幸的是远程。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-08_568f407047464.png)
图 2 协议声明
下面是 XML 生成的协议声明:
~~~
<uap:Extension Category="windows.protocol">
<uap:Protocol Name="com.contoso.showproduct" />
</uap:Extension>
~~~
接下来,您需要添加一些激活代码以便启动使用新的协议时,库存应用程序能够做出适当响应。因为这就是其中路由所有激活,代码应归属到库存应用程序的应用程序类 (App.xaml.cs) 中。您重写要响应协议激活的应用程序类的 OnActivated 方法。图 3 显示该代码如下所示。
图 3 处理深层链接
~~~
protected override void OnActivated(IActivatedEventArgs args)
{
Frame rootFrame = CreateRootFrame();
if (args.Kind == ActivationKind.Protocol)
{
var protocolArgs = args as ProtocolActivatedEventArgs;
rootFrame.Navigate(typeof(ProtocolActivationPage), protocolArgs.Uri);
}
else
{
rootFrame.Navigate(typeof(MainPage));
}
// Ensure the current window is active
Window.Current.Activate();
}
~~~
检查传入 IActivatedEventArgs 以查看是否协议激活的类型。如果是,您将类型转换为 ProtocolActivatedEventArgs 传入的参数和发送拖到 ProductDetails 页面上传入的 URI。ProductDetails 页设置来分析 URI (例如,com.contoso.showproduct:Details 吗?ProductId = 3748937 并显示相应的产品详细信息。此时,库存应用程序已准备好处理传入的深层链接。
完成此方案中的最后一步是启用到库存应用程序的深层链接到销售的应用程序。这是过程的最简单一部分。销售应用程序只是到库存应用程序使用 Launcher.LaunchUriAsync API 对深层链接。下面是该代码可能如下所示:
~~~
Uri uri = new Uri("com.contoso.showproduct:?ProductId=3748937");
await Launcher.LaunchUriAsync(uri);
~~~
## 应用程序之间共享数据
有应用程序需要共享数据但不一定的方案涉及向用户发送到另一个应用程序。例如,我的示例销售应用程序可以显示按区域和甚至深入了解一些特定的商店的销售。显示此数据按产品分类时它会很有用的存储区或区域中可用的该产品的单位数。获取此数据的最佳来源是库存应用程序中,但在这种情况下启动库存应用程序会中断 ux。这是完全方案 AppService 扩展的排序 ([bit.ly/1JfcVkx](http://bit.ly/1JfcVkx)) 用于处理。
其原理很简单: 库存应用程序提供了销售应用程序可以调用"服务"。销售应用程序使用此服务来查询它具有的数据清单应用程序。销售应用程序一次建立,与清单应用程序之间的连接可以保持打开状态,只要销售应用程序尚未被挂起。
## 创建清单应用程序服务
让我们看一下如何清点应用程序创建并发布它要提供的应用程序服务。应用程序服务基本上是专用的后台任务。因此为了添加应用程序服务将 Windows 运行时组件 (通用 Windows) 项目添加到包含库存应用程序的 Visual Studio 解决方案。您可以在 Visual Studio 在 Visual C# 的添加新项目窗口中找到 Windows 运行时组件项目 |Windows |通用。项目模板是在其他语言的类似的位置。
在新的 Windows 运行时组件项目,您将添加一个名为 InventoryServiceTask 的新类。因为,如前面所示,您希望此代码在后台运行而不显示 UI,应用程序服务是专用的后台任务。若要告诉操作系统 InventoryServiceTask 是后台任务,只需实现 IBackgroundTask 接口。IBackgroundTask 接口的 Run 方法将库存应用程序服务的入口点。在这里,您将延迟以便知道该任务应保留周围的只要客户端 (销售的应用程序) 需要它的操作系统。您还附加到应用程序特定于服务 RequestReceived 事件的事件处理程序。此事件处理程序将调用任何客户端发送来处理此服务的请求的时间。图 4 显示初始化的库存应用程序服务的代码如下所示。
图 4 初始化 Run 方法中的库存应用程序服务
~~~
namespace Contoso.Inventory.Service
{
public sealed class InventoryServiceTask : IBackgroundTask
{
BackgroundTaskDeferral serviceDeferral;
AppServiceConnection connection;
public void Run(IBackgroundTaskInstance taskInstance)
{
// Take a service deferral so the service isn't terminated
serviceDeferral = taskInstance.GetDeferral();
taskInstance.Canceled += OnTaskCanceled;
var details = taskInstance.TriggerDetails as AppServiceTriggerDetails;
connection = details.AppServiceConnection;
// Listen for incoming app service requests
connection.RequestReceived += OnRequestReceived;
}
}
}
~~~
现在让我们看看 RequestReceived 处理程序的实现。再次重申,只要请求派上用场需要延迟。一旦完成后将释放此延迟处理传入的请求。货币符号的应用程序服务客户端和应用程序服务之间是通信的一个称为 ValueSet 的数据结构。ValueSets 是可以执行如整数、 浮点数、 字符串和字节数组的简单类型的键/值字典。
图 5 显示清单应用程序服务如何处理传入的请求。它将检查命令的传入消息,然后将使用正确的结果进行响应。在这种情况下,您显示该服务响应的产品和最后一个时间单位数与它所具有的数据的 GetProductUnitCountForRegion 命令已更新。该服务可能也是从 Web 服务中获取此数据或者只从脱机缓存中检索它。比较有利的一点是客户端 (销售的应用程序) 不需要知道或在意从数据的用武之地。
图 5 库存应用程序接收请求
~~~
async void OnRequestReceived(AppServiceConnection sender,
AppServiceRequestReceivedEventArgs args)
{
// Get a deferral so we can use an awaitable API to respond to the message
var messageDeferral = args.GetDeferral();
try
{
var input = args.Request.Message;
string command = input["Command"] as string;
switch(command)
{
case "GetProductUnitCountForRegion":
{
var productId = (int)input["ProductId"];
var regionId = (int)input["RegionId"];
var inventoryData = GetInventoryData(productId, regionId);
var result = new ValueSet();
result.Add("UnitCount", inventoryData.UnitCount);
result.Add("LastUpdated", inventoryData.LastUpdated.ToString());
await args.Request.SendResponseAsync(result);
}
break;
// Other commands
default:
return;
}
}
finally
{
// Complete the message deferral so the platform knows we're done responding
messageDeferral.Complete();
}
}
// Handle cancellation of this app service background task gracefullyprivate void OnTaskCanceled(IBackgroundTaskInstance sender,
BackgroundTaskCancellationReason reason)
{
if (serviceDeferral != null)
{
// Complete the service deferral
serviceDeferral.Complete();
serviceDeferral = null;
}
}
~~~
也显示在 图 5 是取消处理程序的实现。很重要的应用程序服务放弃受理正常取消请求时的延迟。取消应用程序服务后台任务的可能情况可能是因为客户端关闭应用程序服务连接或系统资源不足。无论哪种方式,可确保正常取消,取消并不被视为崩溃由平台。
任何人都可以调用的库存应用程序服务之前,必须将其发布并为其提供一个终结点。首先,您在库存应用程序项目添加到新的 Windows 运行时组件的引用。接下来,您的应用程序服务将声明添加到清单应用程序项目,如中所示 图 6。入口点设置为 InventoryServiceTask 类的完全限定名和名称是将用于标识此应用程序服务终结点的名称。这是客户端将用于到达它的相同名称的应用程序服务。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-08_568f40705f2bc.png)
图 6 应用程序服务声明
下面是生成的应用程序服务声明的 XML:
~~~
<uap:Extension Category="windows.appService"
EntryPoint="Contoso.Inventory.Service.InventoryServiceTask">
<uap:AppService Name="com.contoso.inventoryservice"/>
</uap:Extension>
~~~
另一条客户端将需要与库存应用程序服务进行通信是信息的库存应用程序的包系列名称。获取此值的最简单方法是使用 Windows.ApplicationModel.Package.Current.Id.FamilyName API 在库存应用程序。我通常只是输出该值设置为调试窗口并从该处选取它。
## 调用应用程序服务
现在,库存应用程序服务已到位,您可以从销售应用程序调用它。若要调用客户端的应用程序服务可以使用 AppServiceConnection API。AppServiceConnection 类的实例需要的应用程序服务终结点的名称和包系列名称在服务所在的包。将这两个值视为应用程序服务的地址。
图 7 显示销售应用程序的代码用于连接到的应用程序服务。请注意 AppServiceConnection.AppServiceName 属性设置为终结点名称在清单应用程序的包清单中声明。此外,清单应用程序的包系列名称均被插入到 AppServiceConnection.PackageFamilyName 属性。一旦准备就绪后,调用 AppServiceConnection.OpenAsync API 以打开的连接。OpenAsync API 返回完成后的状态,并使用此状态来确定是否已成功建立连接。
图 7 调用库存应用程序服务
~~~
using (var connection = new AppServiceConnection())
{
// Set up a new app service connection
connection.AppServiceName = "com.contoso.inventoryservice";
connection.PackageFamilyName = "Contoso.Inventory_876gvmnfevegr";
AppServiceConnectionStatus status = await connection.OpenAsync();
// The new connection opened successfully
if (status != AppServiceConnectionStatus.Success)
{
return;
}
// Set up the inputs and send a message to the service
var inputs = new ValueSet();
inputs.Add("Command", "GetProductUnitCountForRegion");
inputs.Add("ProductId",productId);
inputs.Add("RegionId", regionId);
AppServiceResponse response = await connection.SendMessageAsync(inputs);
// If the service responded with success display the result and walk away
if (response.Status == AppServiceResponseStatus.Success)
{
var unitCount = response.Message["UnitCount"] as string;
var lastUpdated = response.Message["LastUpdated"] as string;
// Display values from service
}
}
~~~
连接后,客户端发送的应用程序服务的一组值中 ValueSet 使用 AppServiceConnection.SendMessageAsync API。请注意,在设置的值中的命令属性设置为 GetProductUnitCountForRegion。这是应用程序服务可以理解的命令。SendMessageAsync 返回包含设置的值发回的应用程序服务的响应。解析出 UnitCount 和上次更新值并将其显示。就是这样。这是与应用程序服务进行通信所需的全部。将 AppServiceConnection 放在 using 块。这将调用 Dispose 方法在 AppServiceConnection 上尽快 using 块结束。调用 Dispose 是说它已完成的应用程序服务的通话和它现在可以终止该客户端的方法。
## 等一等,Microsoft 使用这些 Api 吗?
当然,Microsoft 使用这些 Api。作为 Windows 10 的一部分提供的大多数 Microsoft 应用程序实际上是通用的 Windows 平台应用程序。这包括如照片、 相机、 邮件、 日历、 Groove 音乐和应用商店的应用程序。开发人员编写这些应用程序使用许多此处所述实现集成方案的 Api。例如,是否注意到在 Groove 音乐应用程序的"在存储区中的 Get 音乐"链接吗? 如果点击或单击该链接 Groove 音乐应用程序使用 Launcher.LaunchUriAsync API 访问应用商店应用程序。
另一个典型示例是设置应用程序。当您进入帐户 |您的帐户和,请尝试使用相机拍照新配置文件,它使用称为 Launcher.LaunchUriForResultsAsync API 来启动相机应用程序要执行该图片。LaunchUriForResultsAsync 是一种专用的形式的 LaunchUriAsync aka.ms/launchforresults 更多详细信息中所述。
大量的应用程序还使用应用程序服务将信息传递给 Cortana 实时。例如,当应用程序尝试安装 Cortana 应响应的语音命令,它实际调用应用程序由 Cortana 提供服务。
## 总结
Windows 10 附带了功能强大的工具以帮助在同一个设备上运行的应用程序之间的通信。这些工具将不受限制或限制对哪些应用程序可以彼此通信,或者它们可以交换的数据类型。这是非常相像设计使然。目的是让应用程序定义他们自己的约定与每个其他和扩展对方的功能。这还允许应用程序开发人员将其应用程序分解为较小的、 分解易于维护、 更新和使用的体验。这是非常重要,因为用户越来越多地跨多个设备 live 他们生活和使用他们认为是一项任务到最适合的设备。所有这些 Api 是还通用的这意味着它们的工作在台式计算机、 便携式计算机、 平板电脑、 手机和很快 Xbox、 面中心和 HoloLens 上。
* * *
Arun Singh *是通用的 Windows 平台构建团队的高级项目经理。关注他的 Twitter: [@aruntalkstech](https://twitter.com/@aruntalkstech)或阅读他的博客 [aruntalkstech.com](http://aruntalkstech.com/)。*
通知 – Windows 10 中的自适应和交互式通知
最后更新于:2022-04-01 06:55:37
WINDOWS 10 2015 年特别版
此文章由机器翻译。
# 通知 - Windows 10 中的自适应和交互式通知
通过 [Thomas Fennel](https://msdn.microsoft.com/zh-cn/magazine/mt149362?author=Thomas+Fennel) |Windows 2015 年
在开发人员的工具箱影响用户实施中的几个工具喜欢通知。它们是否渗透到操作系统中的体验 Windows mobile、 Windows 桌面上,Xbox 或甚至 HoloLens。没有通知向用户提供不可否认诱饵。从帮助完成某项任务例如回复输入一条消息,与提供简单和及时信息,如新闻标题和甚至取悦他们提供它们实际上并不希望的体验 — 例如 Cortana 提醒 — 通知向用户提供值和与您的应用程序对它们进行沟通。
## 什么是 Windows 中的通知?
通知表示多种类别的整个操作系统的用户合作。从用户的角度来看,通知都包含在许多体验。
图块是最图标的窗体的通知的 Windows 操作系统。您在其他外观造型和设备类型在 Windows 桌面和移动和在各种情形下的开始屏幕上看到磁贴。图块向用户提供以下几个好处。
首先,它们是启动应用程序使用主磁贴的快速方法 — 这些是您从固定应用程序列表直接到开始接触和待定或右键单击列表中的应用程序的磁贴。它们还作为一种方法以获取直接对内容使用辅助磁贴的应用程序中更深入地 — 这些都是一名开发人员会与用户同意的情况下从应用程序中以编程方式固定磁贴。
可以说是更重要的是图块能够通过该磁贴本身,通过动态磁贴提供从应用程序中的内容中提供与客户合作。这些为您提供一种方法来访问用户没有它们实际启动您的应用程序 — 正在天气预报和您最喜欢的团队的赛事比分老套的示例。获取该信息快速地在开始菜单上的一个地方可以取悦用户。
Toast 是在移动设备的顶部或右下角的桌面屏幕弹出通知。它们是查找让用户与应用程序通过启动它的中断通知。在 Windows 10 之前点击 toast 通知可能仅启动用户到应用程序与开发人员在创建通知时无法设置某些静态参数。此外,在 Windows 10 之前没有移动通知称为警报和创建用户不得不在干别的事情之前做出响应的较大的模式对话框的提醒。这两个类似于 toast,并已被融入调用操作所需的 Toast 通知的类别。
徽章是通知的最终类型。您所处位置通常在应用程序中的丢失项的计数在锁屏上主要看到徽章。有时它们表示状态的小标志符号或者 — 思考的感叹点或其他类似。在主和辅助磁贴还表示徽章。
## 如果东西还没坏,问题就不用修理
当我们开始研究自适应和交互式通知时,我们已卖力根据我们听到有关的状态的同时在 Windows Phone 和 Windows 8 上的通知开发人员社区的反馈。我们不想创建新的东西只是因为...我们曾经所有生活所在,通过在过去,它是我们如何得到与此类大通知技术、 基础结构和 Windows Phone 和 Windows 桌面之间的开发人员模型之间的差异。而是面向 Windows 10 我们侧重于开发人员喜欢有关这两个平台中的现有通知框架和作出这样做的时候我们需要,而不是简单地尝试完全摆脱我们旧的承诺。因为我们不只启动 Windows 10 是有趣的时候,我们也已集成到一个平台团队的 Windows Phone 和 Windows 团队。在这一转换,它不能总是轻松地采用此类原则性方法,但我们知道它是国际义人将这两个领域的最佳组合在一起,并将该结果 — 自适应和交互式通知表示"一个 Microsoft"方法。
## 不能缩放磁贴和 Toast 模板目录
开发人员那如何设计这些磁贴和 toast 通知? 以前版本的 Windows 有灵活性相对较差的一系列模板我们将放入该磁贴和 toast 模板目录。这些模板允许开发人员能够轻松、 经济地创建视觉上与 Windows 设计语言一致的通知。但是,若要创建的映像和开发人员可能想的文本配置的所有可能排列,我们最终建立数百个几乎完全相同的模板。
图 1 列举了我们在 Windows Phone 8.1 和 Windows 8.1 中提供的磁贴目录。Text01 是单个行中使文本换行。Text02 是非换行文本的四个单独的行。Text03 是具有单个行中使文本换行的标头。Text04 是具有三行非换行文本的标头。这些显然不会扩展到开发人员可能希望每个可能组合。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-08_568f406f0a565.png)
图 1 从磁贴模板的四个模板目录中提供样式和布局中只有细微的差异
例如,如果您需要两行文本换行吗? 遗憾的是,这并不是目录的一部分这样说来使用仅限映像的模板和呈现自定义位图。但是,从而会产生模糊文本时缩放到不同的分辨率要高得多的数据使用情况时在后台任务中生成位图时从云,以及对性能的影响和不可靠,无法下载。
因为存在实际上只有两个样式,toast 是问题甚至多多。没有从技术上讲八个模板,但它们细分到 toast 与映像或映像,而 toast 中所示 图 2。从开发人员的反馈表明不只是两种布局不足够灵活 toast,没有交互式甚至以简单方式。相当于文字量较在其中显示 toast — 说三、 四行 — 无法容易地消耗在小屏幕上因为我们只介绍了前两个文本行最多。即使基本交互性如能够展开以显示更多的内容的通知不可能与现有的框架。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-08_568f406f2e1a8.png)
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-08_568f406f7c289.png)
图 2 Toast 模板中的两个模板目录
## 不是每个开发人员 (或可以承受) 若要创建丰富的通知
模板解决重要的问题,因为设计、 开发和测试自定义绘制如动态磁贴通知是具有挑战性且成本高昂。我们通知的平台上的各种外观造型和屏幕密度运行和我们支持五个不同的平铺大小和两个 toast 大小,其中所有需要自定义设计、 开发和测试。模板可以因为想要创建通知我们模板语言适合开发人员可以受益最少的开发成本和几乎为零测试成本来缓解这一困难并我们采用以确保它们看起来将其既美观又具备跨所有屏幕的负担。
开发人员无需担心边距、 填充、 字体大小或权重 ;他们可以通过粘贴一些 xml 并更改某些 特性创建既美观又具备并与我们的语言一致的内容。
一次是功能强大需要提供一些灵活的开发人员集成带有其自己的品牌的内容。开发人员花费大量资金和时间创建独特的外观和生成的品牌得以吸引用户。突出显示该品牌是工作的我们项核心原则构建。
## 这对于模板意味着什么?
Windows 10 中的模板有效地服务于只有一个主要用途: 若要针对特定的磁贴大小。在 Windows 10 桌面和移动,我们有小型、 中型和宽磁贴。在桌面中我们还提供其他大小对于大型的图块。我们认为这些磁贴在逻辑 4-units-wide-by-4-units-high 网格方面。较小的磁贴在该网格上占据 1 x 1 单位 — 小方块,真正 — 因此较小的名称。中等磁贴占用该网格中或中等方块上的 2 x 2 单位。是否理解一种趋势吗? 宽磁贴是在该网格中的 4 x 2 单位和大型的图块是完整的 4x4 单位。
我们已在设计时自适应和交互式通知,我们得出的结论是我们可以采取各种措施来折叠到只是大小的关键核心的目录。我们最终建立用于磁贴的只有四个模板 — TileSmall、 TileMedium、 TileWide 和 TileLarge — 和一个用于 toast 模板: ToastGeneric。在将来我们希望进一步折叠和具有内容所在之间所有磁贴大小相同的方案的 TileGeneric 模板。然后开发人员可以只是提供一个模板用于其磁贴。
在以前版本的 Windows 中,模板还提供定义动画特征的整个图面。必须以显示图像通过它循环访问集合的动画的图块将具有其自己的模板。同样,若要显示的缩略图一次设置动画效果和淡入集合所需的图块需要另一个模板。现在动画的处理也是通过对新的提示-* 我们引入了,我稍后将讨论其中的属性。
即使有了所有这些我们将不要弃用的旧模板目录。如果开发人员无需更改的服务器或用于构造其通知客户端代码升级到新通用 Windows 平台 (UWP) Windows 10 中,应用程序将继续工作在 Windows 10 mobile 上的出色和桌面。事实上,一些以前不起作用一致地或根本移动和桌面之间现在很好地工作。例如,正确地在 Windows Mobile 10 上使用任何 ToastImageAndText0 * 模板其中该层以前被省略的通知中显示的图像。
## 自适应和交互式通知
Windows 10 中我们发展我们通知的故事来通过引入三个主要功能提供更丰富的开发人员体验和用户体验。
第一种是自适应磁贴/toast,它提供一个灵活的架构来生成更直观地丰富的通知并使其在不同外观造型自适应显示。
第二个是交互式的 toast,提供一种简单的交互创建 toast 通知,这样用户可以执行快速的操作或通知中的嵌入式答复而无需激活该应用程序并要求用户从他们当前的操作的上下文切换的方法。
第三个是允许应用程序订阅有关 toast 通知的历史记录更改的事件以便时由系统还是用户处理其自己的 toast 通知应用程序可以获得通知。实质上这是一种方法要了解为其应用程序在操作中心内已更改的内容。
## 自适应动态磁贴和操作中的自适应和交互式 Toast 通知
我将使用新的自适应和交互式通知来演示如何构建展示磁贴的关键方面,并且使用实际的应用场景的 toast 的典型项目。具体而言,我将简要介绍可以使用电子邮件应用程序中的新通知的类型。
我将从开始您的电子邮件应用程序的磁贴。如何创建该磁贴本身,通过您的主磁贴的应用程序清单或通过辅助磁贴的 Api,根据我们您尚未在进行任何重大更改时在 Windows 10 版本中,因此我不打算深入了解如何执行这些操作,因为它们已经存在完备。磁贴和 toast 布局定义是使用语义的 XML 架构,通常称为通知负载。实际上,我将关注上为图块是如何创建使用新的外观更丰富的磁贴体验磁贴模板和相应的 XML 负载。
我将创建新的电子邮件通知控件为用户显示的自适应的磁贴通知。吸引用户的最好方式是文本的为其提供的新消息由于最后一次打开它们结合使用的应用程序的消息是文本的从与之进行计数和几行中的电子邮件正文。图 3 显示如下 Windows 10 桌面上的所有四个大小。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-08_568f406f9d399.png)
图 3 小型组织、 中、 宽和大 10 的 Windows 桌面上的磁贴
图 4 描述表示中的图块的通知负载 图 3。
图 4 创建中等规模的自适应磁贴的 XML 负载
~~~
<binding template="TileMedium" branding="logo">
<group>
<subgroup>
<text hint-style="caption">Matt Hidinger</text>
<text hint-style="captionsubtle">Photos from our trip</text>
<text hint-style="captionsubtle">Check out these awesome photos
I took while in New Zealand!</text>
</subgroup>
</group>
<text />
<group>
<subgroup>
<text hint-style="caption">Lei Xu</text>
<text hint-style="captionsubtle">Build 2015 Dinner</text>
<text hint-style="captionsubtle">Want to go out for dinner after
Build tonight?</text>
</subgroup>
</group>
</binding>
~~~
有几个有意思的操作中需要注意 图 4。
首先,仅显示中等磁贴,看到在 TileMedium 绑定中,因为所有四种大小的 XML 相当长的负载。以重新生成所示的所有图块 图 3, ,将需要也使用 TileSmall、 TileWide 和 TileLarge 模板,虽然它们具有每个非常相似的内容。您可以将所有这些绑定到一个通知负载。
其次,是实际的通知中的内容不是在该图块上显示。您可以看到这由两个不同组的 和 标记表示。为什么会这样呢? 因为此图块可能会显示在多个屏幕密度,因此我提供了详细信息以防它获取可显示更多的内容的高密度屏幕上显示。 和 标记可帮助系统可以知道哪些内容要放置在一起在语义上使事情不会剪切掉奇怪放置 — 它是您的方法来描述您想要尽量将显示在一起的信息"单元"。
要注意的第三个问题是在负载中间本身悬挂的文本元素。这是实际指定一个简单的空行的方式在大型磁贴示例中可以看到。
最后的提示-* 可以在此负载中看到我之前提到的元素。这些是全新的灵活性我们引入了可帮助您执行某些操作 (如中所示的简单文本样式有很大一部分 图 5。大量的提示,您可以指定图像的不透明度等内容、 裁剪和偶数就应该的是个人资料照片如何进行动画处理图块上的项的某些特定环境。在 MSDN 博客上提供了可用提示及其他图块详细信息的详细信息 [bit.ly/1NYvsbw](http://bit.ly/1NYvsbw)。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-08_568f406fb81f6.png)
图 5 在左侧,而不是在右侧的高密度屏幕低密度的屏幕上的中等磁贴
若要进一步说明有关的信息密度,这一点 图 5 是举例说明如何从负载 图 4 低密度高密度屏幕与屏幕上显示。我知道似乎中等磁贴旁边大型的磁贴,但在现实生活中的表示形式通常在价格更低的旗舰产品手机上找到一个高密度屏幕与手机上找到一个低密度的屏幕上的中等磁贴。
现在我将转到第二个有趣和有吸引力所无法做的事情,这次是使用具有自适应性并交互式 toast 通知。同样,与该磁贴 Api,在您创建的 toast 通告程序和 toast 对象的方法中为 nothing 已更改 toast Api 中。就像磁贴,什么是真正新增此处是可以使用这些 Api 使用的负载。
您可以创建当接收到新的电子邮件时显示并为用户提供了一些即刻这两个,从而几行文本从电子邮件和几个简单的快速操作要在电子邮件自身上执行一个 toast 通知。两个人们做封电子邮件中的最常见的事情是要将项目标记为已读,因此它们无需在更高版本,请参阅其邮件列表中和立即删除邮件时再次行业关注它。在 Windows 10 桌面上,这种 toast 通知将如下所示 图 6。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-08_568f406fda3c5.png)
图 6 具有自适应性并交互式 Toast 可能会看到电子邮件应用程序使用
中的 XML 图 7 就会生成通知中所示 图 6。
图 7 自适应和交互式 Toast 可能会看到电子邮件应用程序使用
~~~
<toast>
<visual>
<binding template="ToastGeneric">
<text>Andrew Bares</text>
<text>Ideas for blog posts and the template visualizer.</text>
<text>Hey guys, I've got some great ideas for the blog and
some feature ideas for the...</text>
<image placement="AppLogoOverride" hint-crop="circle" src="AndrewBares.png" />
</binding>
</visual>
<actions>
<action activationType="background" content="Mark Read" arguments="read" />
<action activationType="background" content="Delete" arguments="delete" />
</actions>
<audio src="ms-winsoundevent:Notification.Mail"/>
</toast>
~~~
如使用磁贴通知负载前所示,有一些有趣的新问题要注意从 toast 负载中 图 7, ) 以及。
首先,与不同的是以前的模板,您可以自由地指定文本元素并他们并不需要其自己的 Id。我创建了三行文本 toast 通知中使用三个单独的文本元素。
其次,请注意第一行文本加粗而不是所有后续行。现在,您不能使用所有的提示-* 因此此文本样式始终之前将一直应用 toast 为将来的版本在那里我们会在启用更多提示和样式 toast 文本中显示 toast、 磁贴通知上可用的样式。但是,您可以使用一些提示。例如,请注意该提示裁剪属性运作此处我可裁剪 Andrew 通过使用它在组合中,我可以 AppLogoOverride 放置属性显示为一个很好的圆圈的图像来代替能够正常显示应用程序徽标图像。可用的提示和其他 toast 通知的详细信息的详细信息可在 MSDN 博客上[bit.ly/1N3o7GY](http://bit.ly/1N3o7GY)。
最后,在负载操作部分中,请注意如何有使用电子邮件执行常见任务的人员使用单个操作元素创建的两个按钮。参数是应用程序在单击按钮和调用应用程序时将收到。在这种情况下,我使用背景 activationType 因为我想要处理这些操作在应用程序的后台任务。或者,您可以让如果您想要启动该应用程序无法完成该操作的前景 activationType 或协议 activationType 如果您想要调用某个 Web 站点或通过标准协议启动应用程序到应用程序进行通信。
现在,我已创建显示通知所需的 XML 负载,我需要处理上此交互式 toast 通知的用户所采取的操作。
若要启动,因为我选择背景 activationType,我需要我可以在其中执行代码的后台任务。该任务需要在应用程序 Package.appxmanifest,声明中所示 图 8。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-08_568f4070095a7.png)
图 8 声明后台任务以处理在 Package.appxmanifest 中的交互式 Toast 操作
然后,一旦在 Package.appxmanifest 中注册该任务,您可以将代码添加到您的后台任务来实际处理用户操作。在 图 9 您可以看到可将您自己的代码来处理操作的简单存根。
图 9 句柄参数或后台任务中的用户输入
~~~
namespace Tasks
{
public sealed class ToastHandlerTask : IBackgroundTask
{
public void Run(IBackgroundTaskInstance taskInstance)
{
// Retrieve and consume the pre-defined arguments and user inputs here.
var details = taskInstance.TriggerDetails as NotificationActionTriggerDetails;
var arguments = details.Arguments;
// Handle either marking the mail as read or deleting it from the database.
}
}
}
~~~
现在您有应用程序可以动态地在您的图标上显示吸引人视觉的内容和加入针对其最快速的用户通常所需的操作使用 toast。您的应用程序是更有用且很不一般吧给用户,并且它们可以快速获取新信息和不需要在从当前做了什么应用程序的上下文切换与您的体验进行交互。我们期待到一些令人称奇你将需要执行操作并真诚期望您将 Windows 10 中获得更好的用户合作到自适应和交互式通知中。
* * *
Thomas Fennel *是首席项目经理会导致在 Microsoft 在 Windows 开发人员生态系统和平台部门。与他联系 [tfennel@microsoft.com](mailto:tfennel@microsoft.com)。*
应用生命周期 – 通过后台任务和扩展执行使应用处于活动状态
最后更新于:2022-04-01 06:55:35
WINDOWS 10 2015 年特别版
此文章由机器翻译。
# 应用生命周期 - 通过后台任务和扩展执行使应用处于活动状态
通过 [Shawn Henry](https://msdn.microsoft.com/zh-cn/magazine/mt149362?author=Shawn+Henry) |Windows 2015 年
它用于将应用程序的生命周期很容易。当用户启动应用程序时,它无法疯狂的系统上运行: 消耗资源、 弹出窗口,并通常执行它而不考虑其他人高兴。如今,事情要更棘手。在移动优先世界中,应用程序被限制为定义的应用程序生命周期。此生命周期指定当应用程序可以运行,但大多数情况下它不能 — 如果应用程序不是当前用户执行的操作,它不允许运行。
在大多数情况下,这是很好 — 用户知道已应用程序不是在消耗能量或采用削弱性能。对于应用程序,操作系统什么一直都很好的做法,应用程序进入停止稳定状态在不活动的使用时强制实施。原因在于应用程序模型中通用 Windows 平台 (UWP) 需要从最低最终设备如电话和物联网 (IoT) 设备扩展到功能最强大的台式计算机和 Xbox 尤其重要。
对于复杂的应用程序,现代应用程序模型可能看上去限制性刚开始,但正如本文将介绍,有几种方法的应用程序可以展开框并运行 (完成的任务和传递通知),甚至当不在前景中。
## 应用程序生命周期
在传统 Win32 和.NET 桌面开发中,应用程序通常是在两种状态之一:"正在运行"或"未运行"和大多数情况下它们正在运行。这似乎很明显,但思考的即时消息等 Skype 应用程序或类似 Spotify 的音乐应用: 用户启动它、 执行某些操作 (发送消息或搜索音乐),则响起和执行其他操作。同时,Skype 位于在等待消息进入,后台并且 Spotify 保持播放音乐。这与花费的大部分时间中的状态不运行的现代应用 (例如 Windows 商店应用程序基于 UWP),完全不同。
Windows 应用程序都在三种状态之一: 正在运行、 挂起或未运行,如中所示 图 1。当用户启动 Windows 应用程序时,例如通过开始菜单上的磁贴上点击应用程序被激活并进入运行状态。只要用户与应用程序进行交互时,它将保持处于运行状态。如果用户导航离开应用程序或将其降至最低,激发的挂起的事件。这是应用程序进行序列化时它已恢复或重新激活,如应用程序或部分填充扩展窗体数据的当前页它可能需要的任何状态的机会。当应用程序处于挂起状态时,其进程和线程由 Windows 挂起,不能执行。当用户导航回该应用程序时,应用程序线程会被解冻和应用程序恢复运行状态。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-08_568f406ec4e6b.png)
图 1 Windows 应用程序生命周期
如果应用程序处于挂起的状态,但是它使用 (通常是内存) 的资源,则需要用作其他用途,如运行另一个应用程序,该应用程序移到未运行状态。
从应用程序执行的角度看,挂起和未运行状态之间的区别是是否允许该应用程序驻留在内存中。当只是挂起应用程序时,它的执行被冻结,但所有其状态信息保留在内存中。当应用程序未运行时,它从内存中删除。当从移动应用程序挂起到未在运行时,会不触发任何事件,因为很重要的应用程序进行序列化所有它从内存中,所需的状态信息以防未在运行从重新激活它。
图 2 显示发生的资源使用情况与应用程序生命周期的转换。应用程序激活时,它开始占用内存,通常达到相对稳定比尔。当挂起应用程序时,其内存使用量通常出现故障 — 缓冲区和使用的资源的发行,和 CPU 占用率变为零 (由操作系统强制执行)。当在移动应用程序从挂起到未运行时,内存和 CPU 的使用将转到零,再次由操作系统强制执行。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-08_568f406ed1109.png)
图 2 应用程序生命周期和资源使用情况
大量的 RAM 和大型页文件的许多桌面系统上它并不常用 — 但不是不可能 — 从内存中,但这种转换中删除的应用程序是在移动设备和其他资源受限的设备上更常见。为此,务必测试 UWP 应用程序在各种设备上。Windows 仿真程序附带使用 Visual Studio 会非常有用对于这一点 ;它允许开发人员能够与目标设备作为小 512 MB 的内存。
## 扩展的执行
我所述的应用程序生命周期是有效 — 如果它们不会使用,应用程序不占用资源 — 但它会导致哪些应用程序需求不能完成其中的方案。例如,社会或通信的应用程序的一个典型用例是登录并同步一组云数据 (联系人、 源、 对话历史记录和等)。与基本应用程序生命周期所述,若要下载联系人、 用户需要保持该应用程序打开和在前台中的全部时间 ! 另一个示例可能是导航或适用性的应用程序需要跟踪用户的位置。只要用户切换到不同的应用程序或将设备置于其 pocket 时,这将不再起作用。需要有一种机制以允许应用程序运行较长时间。
通用 Windows 平台引入了扩展的执行来帮助进行这些类型的情况的概念。有两种情况下可以使用扩展的执行的位置:
1. 在应用程序处于运行状态时的正则前台执行期间的任何时刻。
2. 该应用程序接收到挂起的事件后 (是操作系统以将该应用程序移到挂起状态) 在应用程序的挂起事件处理程序。
这两种情况的代码是相同的但应用程序的行为有点以不同的方式在每个。在第一种情况下,应用程序处于运行状态,即使发生 (例如导航离开应用程序的用户) 的程序通常会触发挂起的事件。执行扩展在生效时,应用程序将永远不会收到挂起事件。当释放该扩展插件时,该应用程序将再次变为适合挂起。
与第二个用例,如果应用程序转换到挂起状态,它将保留在挂起状态的扩展的时间。该扩展插件到期后,应用程序将进入挂起的状态无进一步通知。
图 3 演示如何使用扩展的执行来扩展应用程序的 uspending 状态。首先,新 ExtendedExecutionSession 创建并附带的原因和说明。这两个属性用于分配正确的资源设置为该应用程序 (即量的内存、 CPU 和允许它的执行时间) 以及公开有关应用程序在后台执行的操作信息提供给用户。然后,应用程序挂接如果称为 Windows 不再可以支持扩展,例如,如果另一个高优先级的任务如前台应用程序或传入的 VoIP 呼叫,需要资源一个吊销事件处理程序。最后,应用程序请求该扩展插件,并且如果成功,将从开始保存操作。如果拒绝该扩展插件,该应用程序将在执行挂起操作尚未收到的扩展功能,像常规的挂起事件。
图 3 扩展 OnSuspending 处理程序中的执行
~~~
private async void OnSuspending(object sender, SuspendingEventArgs e)
{
var deferral = e.SuspendingOperation.GetDeferral();
using (var session = new ExtendedExecutionSession())
{
session.Reason = ExtendedExecutionReason.SavingData;
session.Description = "Upload Data";
session.Revoked += session_Revoked;
var result = await session.RequestExtensionAsync();
if (result == ExtendedExecutionResult.Denied)
{
UploadBasicData();
}
// Upload Data
var completionTime = await UploadDataAsync(session);
}
deferral.Complete();
}
~~~
图 4 显示这对应用程序生命周期的影响 ; 将对其进行比较 图 2。当应用程序获取挂起事件时,它开始释放或序列化的资源。如果应用程序确定它需要更多时间,并采用一个扩展,它将一直处于挂起状态撤消该扩展插件。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-08_568f406ee23c1.png)
图 4 在扩展的执行过程的资源使用情况
情况 2 中前面所述,执行扩展无需请求仅在挂起的处理程序 ;它可以在任何时刻在应用程序处于运行状态时请求。这可用于当在应用程序知道事先它将需要与前面所述导航布局应用程序可以继续在后台运行。代码非常类似于前面的示例和中所示 图 5。
图 5 扩展在正则执行过程的执行
~~~
private async void StartTbTNavigationSession()
{
using (var session = new ExtendedExecutionSession())
{
session.Reason = ExtendedExecutionReason.LocationTracking;
session.Description = "Turn By Turn Navigation";
session.Revoked += session_Revoked;
var result = await session.RequestExtensionAsync();
if (result == ExtendedExecutionResult.Denied
{
ShowUserWarning("Background location tracking not available");
}
// Do Navigation
var completionTime = await DoNavigationSessionAsync(session);
}
}
~~~
图 6 显示了这种情况下的应用程序生命周期。同样,它也是非常相似。不同之处在于时执行扩展被吊销,, 应用程序将可能迅速转变通过挂起状态进入未运行状态。这是因为在这种情况下,仅由于资源不足,仅通过释放资源可以缓解 (即,从内存中删除该应用程序) 的情况通常撤消该扩展插件。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-08_568f406eee360.png)
图 6 在扩展的执行过程的资源使用情况
## 后台任务
没有应用程序可以在后台中运行的另一种方法,这就是作为后台任务。后台任务是在应用程序中单独实现 IBackgroundTask 接口的组件。这些组件可以没有重量级 UI 框架的情况下执行并 (尽管它们也可以运行进程内与主应用程序可执行文件) 通常执行的单独进程中。
激发相关联的触发器时执行后台任务。触发器是系统事件可以激发并激活应用程序,即使应用程序未运行。例如,可以使用特定时间间隔内 (说,每隔 30 分钟) 生成 TimeTrigger、 应用程序的后台任务将在这种情况下激活时激发该触发器每隔 30 分钟。有许多支持的 Windows,包括这些背景触发器类型的触发器类型: TimeTrigger、 PushNotificationTrigger、 LocationTrigger、 ContactStoreNotificationTrigger、 BluetoothLEAdvertisementWatcherTrigger、 UserPresent、 InternetAvailable 和 PowerStateChange。
使用后台任务是一个三步骤过程: 该组件需要创建,然后在应用程序清单中声明并随后在运行时进行了注册。
通常在单独的 Windows 运行时 (WinRT) 组件项目中与 UI 项目相同的解决方案中实现后台任务。这允许在一个单独的进程,减少开销由组件所需的内存中激活的后台任务。所示的简单实现 IBackgroundTask图 7。IBackgroundTask 是一个简单的界面,用于定义只是一种方法运行。这是在后台任务触发器被触发时调用的方法。方法的唯一参数是一个包含有关激活 (例如,使用 toast 通知的操作相关联的推送通知的负载) 和事件处理程序来处理取消等的生命周期事件的上下文的 IBackgroundTaskInstance 对象。当 Run 方法完成后时,将终止的后台任务。为此,就像前面显示的挂起处理程序中一样是一定要使用的延迟对象 (还关闭 IBackgroundTaskInstance 悬挂) 如果您的代码是异步的。
图 7 BackgroundTask 实现
~~~
public sealed class TimerTask : IBackgroundTask
{
public void Run(IBackgroundTaskInstance taskInstance)
{
var deferral = taskInstance.GetDeferral();
taskInstance.Canceled += TaskInstance_Canceled;
await ShowToastAsync("Hello from Background Task");
deferral.Complete();
}
private void TaskInstance_Canceled(IBackgroundTaskInstance sender,
BackgroundTaskCancellationReason reason)
{
// Handle cancellation
deferral.Complete();
}
}
~~~
在应用程序清单中,还必须注册的后台任务。此注册指示 Windows,但是触发器类型、 入口点和可执行该任务的主机,如下所示:
~~~
<Extensions>
<Extension Category="windows.backgroundTasks" EntryPoint="BackgroundTasks.TimerTask">
<BackgroundTasks>
<Task Type="timer" />
</BackgroundTasks>
</Extension>
~~~
这也可以不深入探讨 XML 通过使用 Visual Studio 附带在清单设计器的情况下完成。
最后,还必须在运行时,注册该任务并显示了 图 8。此处我使用 BackgroundTaskBuilder 对象来注册该任务将激发每隔 30 分钟 TimeTrigger Internet 是否可用。这是触发器的理想的为诸如更新磁贴或定期同步少量数据之类的常见操作类型。
图 8 后台任务注册
~~~
private void RegisterBackgroundTasks()
{
BackgroundTaskBuilder builder = new BackgroundTaskBuilder();
builder.Name = "Background Test Class";
builder.TaskEntryPoint = "BackgroundTaskLibrary.TestClass";
IBackgroundTrigger trigger = new TimeTrigger(30, true);
builder.SetTrigger(trigger);
IBackgroundCondition condition =
new SystemCondition(SystemConditionType.InternetAvailable);
builder.AddCondition(condition);
IBackgroundTaskRegistration task = builder.Register();
task.Progress += new BackgroundTaskProgressEventHandler(task_Progress);
task.Completed += new BackgroundTaskCompletedEventHandler(task_Completed);
}
~~~
后台任务的最大优势也可以是其大麻烦: 由于在后台 (在用户可能需要执行一些重要在前台或该设备处于待机状态时) 运行后台任务,它们是严格的限制内存和他们可以使用的 CPU 时间量。例如,后台任务注册中 图 8 将仅为 30 秒对运行和不能使用超过 16 MB 的内存在设备上有 512 MB 内存 ; 内存上限进行缩放,在设备上的内存量。在开发和实现后台任务时, 务必考虑到这一点。后台任务应进行测试的各种设备,尤其是低端设备、 之前发布的应用程序。有几个要同时请注意其他事项:
* 如果 Battery Saver 是可用并处于活动状态 (通常当电池是低于费用阈值),后台任务不能运行,直到电池过去的电池电量节省阈值重新充电。
* 在以前版本的 Windows 中,将"固定"到锁之前他们之所以能够执行在后台,且在某些情况下,所需的应用程序没有可能是已注册的设备级的后台任务的最大数量。这不再是这种情况在 Windows 10,但应用程序必须始终调用 BackgroundExecutionManger.RequestAcessAsync 来声明其意图在后台中运行。
## 不要联系同步的更好方式
有许多后台操作可完成与任一扩展执行或通过后台任务。通常,是更好的做法尽可能使用后台任务 — — 它们更可靠、 更高效。
例如,上文所述的方案 — 应用程序首次启动时同步数据 — 还可以进行,并且更高效地通过后台任务,在这种情况下使用触发器不熟悉的 Windows 10: 应用程序触发器。
(如 DeviceUseTrigger) ApplicationTrigger 属于一种特殊的类的直接从应用程序的前景部分触发的触发器。这是通过显式调用 RequestAsync 触发器对象上。ApplicationTrigger 是对于应用程序要在应才有机会在后台继续进行如果该应用程序不再位于前台,而该操作不依赖于紧密耦合的前景前台启动操作的情况下特别有用。下面演示举例说明如何可以代替大多数情况下扩展执行 ApplicationTrigger 任务:
~~~
var appTrigger = new ApplicationTrigger();
var backgroundTaskBuilder = new BackgroundTaskBuilder();
backgroundTaskBuilder.Name = "App Task";
backgroundTaskBuilder.TaskEntryPoint = typeof(AppTask).FullName;
backgroundTaskBuilder.SetTrigger(appTrigger);
backgroundTaskBuilder.Register();
var result = await appTrigger.RequestAsync();
~~~
## 总结
本文提供 Windows 10 中的应用程序生命周期和后台执行的概述,并引入了几个新的应用程序可用于在后台运行的机制: 扩展执行和后台任务。后台任务是更好的选择为低端和内存约束设备 (如电话),而扩展的执行是更适用于更高端设备 (如桌面 Pc)。
* * *
Shawn Henry *是通用的 Windows 平台构建团队的高级项目经理。与他联系在 Twitter 上关注:[@shawnhenry](https://twitter.com/@shawnhenry)。*
图形和动画 – Windows 组合支持 10 倍缩放
最后更新于:2022-04-01 06:55:32
WINDOWS 10 2015 年特别版
# 图形和动画 - Windows 组合支持 10 倍缩放
作者 [Kenny Kerr](https://msdn.microsoft.com/zh-cn/magazine/mt149362?author=Kenny+Kerr) | Windows 2015
Windows 组合引擎,又称桌面窗口管理器 (DWM),为 Windows 10 提供了新 API。DirectComposition 是组合的主要接口,但是作为经典 COM API,它对于一般水平的应用开发人员而言很大程度上是难以访问的。全新 Windows 组合 API 基于 Windows 运行时 (WinRT) 构建,并且通过将 Direct2D 和 Direct3D 提供的即时模式图形领域与如今动画及效果有很大改进的保留可视化树进行混合,为高性能渲染奠定了基础。
我首次撰写 DWM 文章要追溯到 2006 年,当时 Windows Vista 还在测试中 ([goo.gl/19jCyR](http://goo.gl/19jCyR))。它允许您控制给定窗口模糊效果的范围,并创建与桌面完美混合的自定义镶边。图 1 显示了 Windows 7 中这一实现的高度。可以使用 Direct3D 和 Direct2D 制作硬件加速渲染,从而为您的应用打造绝妙的视觉效果 ([goo.gl/IufcN1](http://goo.gl/IufcN1))。您甚至可以将 GDI 和 USER 控件的旧领域与 DWM 混合 ([goo.gl/9ITISE](http://goo.gl/9ITISE))。然而,任何敏锐的观察者都会说 DWM 可以提供的更多 — 更多。Windows 7 中的 Windows Flip 3D 功能就是有力的佐证。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-08_568f406e112fd.png)
图 1 Windows Aero
Windows 8 为 DWM 引入称为 DirectComposition 的新 API,它的名称正是向激发其设计灵感的经典 COM API 的 DirectX 系列致敬。DirectComposition 开始向开发人员提供比 DWM 能够提供的画面更加清晰的画面。此外,它还提供了改进的术语。DWM 确实是 Windows 组合引擎,能够在 Windows Vista 和 Windows 7 中制作炫丽的效果,因为它从根本上改变了桌面窗口的渲染方式。默认情况下,组合引擎为每个顶层窗口创建了重定向设计面。我在 2014 年 6 月专栏中对此进行了详细介绍 ([goo.gl/oMlVa4](http://goo.gl/oMlVa4))。这些重定向设计面构成了可视化树的一部分,并且 DirectComposition 允许应用利用这一相同技术为高性能图形提供轻量保留模式 API。DirectComposition 提供了可视化树与设计面管理,允许应用将效果与动画的制作任务转移给组合引擎。我在 2014 年 8 月 ([goo.gl/CNwnWR](http://goo.gl/CNwnWR)) 和 9 月专栏 ([goo.gl/y7ZMLL](http://goo.gl/y7ZMLL)) 中介绍了这些功能。我甚至制作了有关使用 DirectComposition for Pluralsight 实现高性能渲染的课程 ([goo.gl/fgg0XN](http://goo.gl/fgg0XN))。
Windows 8 首次推出 DirectComposition,以及对 API 其余 DirectX 系列的一些显著改进,而且,它还引领了一个全新的 Windows API 时代,将永远改变开发人员看待操作系统的方式。Windows 运行时的推出举世瞩目。Microsoft 预示了全新的构建应用和访问操作系统服务的方式,这将最终终结所谓的 Win32 API,Win32 API 一直以来主导着构建应用和与操作系统交互的方式。Windows 8 起步艰难,但是 Windows 8.1 修复了很多问题,并且 Windows 10 如今提供了更为全面的 API,将满足对构建适用于 Windows 的一级应用(甚至是重要的应用)感兴趣的更多开发人员。
Windows 10 于 2015 年 7 月推出,预告了尚未准备制作的新组合 API。其仍会有变动,因此不能在提交至 Windows 应用商店的通用 Universal Windows 应用中使用。这也正是因为现在可进行制作的组合 API 发生了显著的变化,并且是向好的方向转变。此 Windows 10 更新也是有史以来第一次同一组合 API 在所有规格的产品上可用,这也进一步证明了通用 Windows 平台的通用性。无论您面向的是多显示器的桌面平台,还是置于口袋中的小巧智能手机,这一组合均采用相同的工作方式。
当然,对于 Windows 运行时,每个人都喜欢的一个优点就是,它最终兑现了 Windows 通用语言运行时的承诺。如果您更喜欢用 C# 编码,则可以通过内置于 Microsoft .NET Framework 的支持直接使用 Windows 运行时。如果与我一样,您更喜欢使用 C++,则可以使用没有中间媒介或者成本高昂的抽象化的 Windows 运行时。Windows 运行时构建于 COM 而非 .NET,因此非常适于使用 C++。我将使用针对 Windows 运行时、标准 C++ 语言投射的现代 C++ ([moderncpp.com](http://moderncpp.com/)),但是您可以选择自己喜欢的语言,因为不管怎样,API 都是相同的。我也会提供一些 C# 示例来说明 Windows 运行时如何无缝支持不同的语言。
Windows 组合 API 远离其 DirectX 根。DirectComposition 提供了一个设备对象(效仿 Direct3D 和 Direct2D 设备),而新的 Windows 组合 API 则以排序器开始。但是,其目的相同,都是充当组合资源的工厂。除此之外,Windows 组合与 DirectComposition 非常类似。有一个代表窗口及其可视化树之间关系的组合目标。您离视觉对象越近,差异就越明显。DirectComposition 视觉对象具有提供某种位图的内容属性。位图为以下三项之一:组合设计面、DXGI 交换链或另一窗口的重定向设计面。一个典型的 DirectComposition 应用程序由视觉对象和设计面构成,设计面充当不同视觉对象的内容或位图。如图 2所示,组合可视化树稍微有点怪异。新的视觉对象没有内容属性,而是使用组合画笔渲染。这就造就了更灵活的抽象化。虽然画笔只能像以前那样渲染位图,但至少从概念上而言,可以更高效地创建纯色画笔并可定义更详尽的画笔,采用的方式与 Direct2D 提供可视作图像的效果的方式一样。合适的抽象化非常重要。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-08_568f406e3d503.png)
图 2 Windows 组合可视化树
让我们看一些实际示例,来说明这一切的工作原理并让您大致了解一下可能的情况。同样,您可以选择自己喜欢的 WinRT 语言投射。您可以使用现代 C++ 创建排序器,如下所示:
~~~
using namespace Windows::UI::Composition;
Compositor compositor;
~~~
同样,您可以使用 C# 执行相同的操作:
~~~
using Windows.UI.Composition;
Compositor compositor = new Compositor();
~~~
您甚至可以使用 C++/CX 提供的更炫丽的语法:
~~~
using namespace Windows::UI::Composition;
Compositor ^ compositor = ref new Compositor();
~~~
从 API 的角度看,所有这些都是相同的,仅仅在语言投射方面有一些差异。如今,您基本上可以采用两种方式编写通用 Windows 应用。或许最常见的方法是使用操作系统的 Windows.UI.Xaml 命名空间。如果 XAML 对于您的应用没有那么重要,您还可以直接使用基础应用模型(不依赖于 XAML)。我在 2013 年 8 月专栏 ([goo.gl/GI3OKP](http://goo.gl/GI3OKP)) 中介绍了 WinRT 应用模型。如果使用这种方法,您只需以最小程度实现 IFrameworkView 和 IFrameworkViewSource 接口即可直接开始操作了。图 3 在提供了一个使用 C# 的基本大纲,可方便您入手。Windows 组合还提供了与 XAML 的深入集成,但是让我们先看看简单的无 XAML 的应用吧,因为它可以提供一个更简单的场所来了解组合。我将在本文稍后部分再返回到 XAML。
图 3 C# Windows 运行时应用模型
~~~
using Windows.ApplicationModel.Core;
using Windows.UI.Core;
class View : IFrameworkView, IFrameworkViewSource
{
static void Main()
{
CoreApplication.Run(new View());
}
public IFrameworkView CreateView()
{
return this;
}
public void SetWindow(CoreWindow window)
{
// Prepare composition resources here...
}
public void Run()
{
CoreWindow window = CoreWindow.GetForCurrentThread();
window.Activate();
window.Dispatcher.ProcessEvents(CoreProcessEventsOption.ProcessUntilQuit);
}
public void Initialize(CoreApplicationView applicationView) { }
public void Load(string entryPoint) { }
public void Uninitialize() { }
}
~~~
它位于应用的 SetWindow 方法(参见图 3)内,其中应构造排序器。事实上,这是应用生命周期中最早发生这种情况的点,因为排序器依赖窗口的调度程序,而这是窗口和调度程序最终都存在的点。然后,可通过创建组合目标在排序器与应用视图之间建立一种关系:
~~~
CompositionTarget m_target = nullptr;
// ...
m_target = compositor.CreateTargetForCurrentView();
~~~
应用保持组合目标处于活动状态很重要,所以请务必使其成为 IFrameworkView 实现的成员变量。正如我先前所说,组合目标代表窗口或视图与其可视化树之间的关系。您能对组合目标执行的操作就是,设置根视觉对象。通常,这将会是一个容器视觉对象:
~~~
ContainerVisual root = compositor.CreateContainerVisual();
m_target.Root(root);
~~~
在此我使用的是 C++,其缺少属性语言支持,因此根属性被投射为访问器方法。C# 与属性语法的新增部分非常相似:
~~~
ContainerVisual root = compositor.CreateContainerVisual();
m_target.Root = root;
~~~
DirectComposition 只提供了一种视觉对象,它支持各种设计面来表示位图内容。Windows 组合提供了表示各种视觉对象、画笔和动画的小类层次结构,然而只有一种设计面,且只能使用 C++ 创建,因为它属于供 XAML 等框架以及更有经验的应用开发人员使用的 Windows 组合 interop API。
视觉对象类层次结构如图 4 所示。CompositionObject 是由排序器支持的资源。所有组合对象可能已为其属性设置动画。视觉对象提供了大量属性,用于控制视觉对象相对位置、外观、裁剪和渲染选项等许多方面。它包含转换矩阵属性,以及用于缩放和旋转的快捷方式。这的确是一个非常强大的基类。相反,ContainerVisual 是一个相对简单的类,只添加了 Children 属性。虽然您可以直接创建容器视觉对象,但是 SpriteVisual 添加了关联画笔的功能,以便视觉对象可以确实地渲染其自己的像素。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-08_568f406e55e13.png)
图 4 组合视觉对象
给定一个根容器视觉对象,我可以创建任意数量的子视觉对象:
~~~
VisualCollection children = root.Children();
~~~
这些还可以是容器视觉对象,但是他们更可能是子画面视觉对象。我可以使用 C++ 中的 for 循环添加三个视觉对象作为根视觉对象的子项:
~~~
using namespace Windows::Foundation::Numerics;
for (unsigned i = 0; i != 3; ++i)
{
SpriteVisual visual = compositor.CreateSpriteVisual();
visual.Size(Vector2{ 300.0f, 200.0f });
visual.Offset(Vector3{ 50 + 20.0f * i, 50 + 20.0f * i });
children.InsertAtTop(visual);
}
~~~
您可以在图 5 中轻松想象应用窗口,然而该代码不会导致渲染任何内容,因为没有画笔与这些视觉对象关联。画笔类层次结构如图 6 所示。CompositionBrush 只是画笔的一个基类,不提供其自己的任何功能。CompositionColorBrush 是最简单的种类,只提供一个颜色属性用于渲染纯色视觉对象。这可能听起来没什么让人振奋的,但是不要忘了,您可以将动画连接到该颜色属性。CompositionEffectBrush 和 CompositionSurfaceBrush 类相关联,但却是更复杂的画笔,因为它们由其他资源支持。对于任何附加的视觉对象,CompositionSurfaceBrush 都会渲染一个组合设计面。它具有控制位图绘制的各种属性,例如内插、对齐和拉伸,更不用说设计面本身了。CompositionEffectBrush 采用多种设计面画笔制作各种效果。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-08_568f406e652fa.png)
图 5 窗口中的子视觉对象
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-08_568f406e81b6e.png)
图 6 组合画笔
创建和应用彩色画笔简单直接。下面是使用 C# 的一个例子:
~~~
using Windows.UI;
CompositionColorBrush brush = compositor.CreateColorBrush();
brush.Color = Color.FromArgb(0xDC, 0x5B, 0x9B, 0xD5);
visual.Brush = brush;
~~~
颜色结构由 Windows.UI 命名空间提供,并显示 alpha、红色、绿色和蓝色作为 8 位颜色值,不同于 DirectComposition 和 Direct2D 对浮点颜色值的偏好。对于视觉对象和画笔,该方法一个比较好的功能是,可以随时更改颜色属性,而且引用相同画笔的所有视觉对象都将自动进行更新。我之前的确暗示过,颜色属性甚至可以制作动画。那么它的工作原理是什么? 接下来我们谈谈动画类。
动画类层次结构如图 7 所示。CompositionAnimation 基类提供了存储命名值以用于表达式的功能。我稍后将详细讨论表达式。KeyFrameAnimation 提供了典型的基于关键帧的动画属性,如持续时间、迭代和停止行为。各种关键帧动画类提供了用于插入关键帧的特定于类型的方法,以及特于定类型的动画属性。例如,ColorKeyFrameAnimation 允许您插入具有颜色值的关键帧以及一个用于控制颜色空间以使其在关键帧之间插入的属性。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-08_568f406e91937.png)
图 7 组合动画
创建动画对象,然后将该动画应用至特定组合对象,这简直太容易了。假设我想为某视觉对象的不透明度制作动画。我可以直接使用 C++ 中的标量值将视觉对象的不透明度设置为 50%,如下所示:
~~~
visual.Opacity(0.5f);
~~~
或者,我可以使用关键帧创建一个标量动画对象,以制作一个从 0.0 至 1.0 的动画变量,代表 0% 到 100%的不透明度:
~~~
ScalarKeyFrameAnimation animation =
compositor.CreateScalarKeyFrameAnimation();
animation.InsertKeyFrame(0.0f, 0.0f); // Optional
animation.InsertKeyFrame(1.0f, 1.0f);
~~~
InsertKeyFrame 的第一个参数是从动画 (0.0) 开始到动画 (1.0) 结束的相对偏移。第二个参数是动画时间线中该点的动画变量的值。因此,该动画将在动画期间将值从 0.0 顺利转变为 1.0。然后,我可以设置该动画的总体持续时间,如下所示:
~~~
using namespace Windows::Foundation;
animation.Duration(TimeSpan::FromSeconds(1));
~~~
动画准备好后,我只需将其连接至我选择的组合对象和属性:
~~~
visual.StartAnimation(L"Opacity", animation);
~~~
StartAnimation 方法实际上继承自 CompositionObject 基类,表示您可以为各种类的属性制作动画。这也是与 DirectComposition 相背离的一点。在 DirectComposition 中,每个可制作动画的属性为标量值和动画对象提供了过多负载。Windows 组合可提供更加丰富的属性系统,这就引入了一些非常有趣的功能。尤其是,它支持写入文本表达式,减少了为制作更有趣的动画和效果所需编写的代码量。这些表达式在运行时进行分析,由 Windows 组合引擎编译,然后高效执行。
假设您需要沿 Y 轴旋转某视觉对象,让其深度表现出来。视觉对象的 RotationAngle 属性(以弧度测量)是不够的,因为它无法制作出包含角度的转换。随着视觉对象旋转,离人眼最近的边会显得较大,而相反方向的边则会显得较小。图 8 显示了说明这一行为的多个旋转对象。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-08_568f406ea8151.png)
图 8 旋转视觉对象
您如何实现此类动画效果? 那么,我们来看看针对旋转角度的标量关键帧动画:
~~~
ScalarKeyFrameAnimation animation = compositor.CreateScalarKeyFrameAnimation();
animation.InsertKeyFrame(1.0f, 2.0f * Math::Pi,
compositor.CreateLinearEasingFunction());
animation.Duration(TimeSpan::FromSeconds(2));
animation.IterationBehavior(AnimationIterationBehavior::Forever);
~~~
线性缓动函数替代了默认的加速/减速功能,以制作持续的旋转动作。然后,我需要使用可以从表达式中引用的属性定义自定义对象。排序器针对这一目的提供了一个属性集:
~~~
CompositionPropertySet rotation = compositor.CreatePropertySet();
rotation.InsertScalar(L"Angle", 0.0f);
~~~
一个属性集也是一个组合对象,所以我可以使用 StartAnimation 方法为我的自定义属性制作动画,就像为任意内置属性制作动画那样简单:
~~~
rotation.StartAnimation(L"Angle", animation);
~~~
我现在有一个 Angle 属性在移动中的对象。现在,我需要定义一个转换矩阵来制作想要的效果,同时委派给针对旋转角度本身的此动画属性。输入表达式:
~~~
ExpressionAnimation expression =
compositor.CreateExpressionAnimation(
L"pre * Matrix4x4.CreateFromAxisAngle(axis, rotation.Angle) * post");
~~~
动画表达式不是关键帧动画对象,因此没有动画变量可能会改变的相对关键帧偏移(基于某些内插功能)。表达式反而仅仅是指可能在更传统的意义上为自身制作动画的参数。当然,由我来定义什么是“前”、“轴”、“旋转”和“后”。我们来看看轴参数:
~~~
expression.SetVector3Parameter(L"axis", Vector3{ 0.0f, 1.0f, 0.0f });
~~~
表达式中的 CreateFromAxisAngle 方法预计旋转某轴并因此围绕 Y 轴定义该轴。它还预计旋转角度,为此我们可以遵从旋转属性集及其动画“Angle”属性:
~~~
expression.SetReferenceParameter(L"rotation", rotation);
~~~
要确保旋转发生在视觉对象中央而不是左边,我需要预先将 CreateFromAxisAngle 创建的旋转矩阵乘以逻辑上将轴移动到旋转点的转换:
~~~
expression.SetMatrix4x4Parameter(
L"pre", Matrix4x4::Translation(-width / 2.0f, -height / 2.0f, 0.0f));
~~~
切记,矩阵相乘不是交替的,所以前矩阵和后矩阵确实就是那样。最后,在旋转矩阵之后,我可以添加一些角度,然后将视觉对象还原至其原始位置:
~~~
expression.SetMatrix4x4Parameter(
L"post", Matrix4x4::PerspectiveProjection(width * 2.0f) *
Matrix4x4::Translation(width / 2.0f, height / 2.0f, 0.0f));
~~~
这满足表达式提及到的所有参数,我现在只需使用表达式动画即可通过 TransformMatrix 属性来为视觉对象制作动画:
~~~
visual.StartAnimation(L"TransformMatrix", expression);
~~~
我已经探讨了创建、填充视觉对象并为其制作动画的各种方式,那么我如果要直接渲染视觉对象的话,该怎么办? DirectComposition 同时提供了预先分配的设计面和稀疏分配的位图(叫做虚拟设计面,按需分配并可调整大小)。Windows 组合似乎没有提供创建设计面的功能。有一个 CompositionDrawingSurface 类,但如果没有外界协助,则无法创建。答案来自 Windows 组合 interop API。如果您只有组件的 Windows 元数据,则 WinRT 类可能会实现无法直接看到的其他 COM 接口。根据对这些掩蔽的接口的了解,您可以在 C++ 中轻松查询它们。当然,这会导致要做的工作更多一点,因为您脱离了 Windows 组合 API 提供给主流开发人员的清洁抽象。我要做的第一件事情是,创建一个渲染设备,并且我将使用 Direct3D 11,因为 Windows 组合尚不支持 Direct3D 12:
~~~
ComPtr<ID3D11Device> direct3dDevice;
~~~
然后,我将准备设备创建标记:
~~~
unsigned flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT |
D3D11_CREATE_DEVICE_SINGLETHREADED;
#ifdef _DEBUG
flags |= D3D11_CREATE_DEVICE_DEBUG;
#endif
~~~
BGRA 支持允许我使用更易上手的 Direct2D API 来通过此设备进行渲染,然后 D3D11CreateDevice 函数自行创建硬件设备:
~~~
check(D3D11CreateDevice(nullptr, // Adapter
D3D_DRIVER_TYPE_HARDWARE,
nullptr, // Module
flags,
nullptr, 0, // Highest available feature level
D3D11_SDK_VERSION,
set(direct3dDevice),
nullptr, // Actual feature level
nullptr)); // Device context
~~~
之后,我需要查询设备的 DXGI 接口,因为这是我创建 Direct2D 设备所需要的:
~~~
ComPtr<IDXGIDevice3> dxgiDevice = direct3dDevice.As<IDXGIDevice3>();
~~~
现在可以创建 Direct2D 设备了:
~~~
ComPtr<ID2D1Device> direct2dDevice;
~~~
此时,我将再次为增加的诊断启用调试层:
~~~
D2D1_CREATION_PROPERTIES properties = {};
#ifdef _DEBUG
properties.debugLevel = D2D1_DEBUG_LEVEL_INFORMATION;
#endif
~~~
我可以先创建一个 Direct2D 工厂来创建该设备。如果我需要创建任何独立于设备的资源,这将会非常有用。在这里我将只使用 D2D1CreateDevice 函数提供的快捷方式:
~~~
check(D2D1CreateDevice(get(dxgiDevice), properties, set(direct2dDevice)));
~~~
渲染设备准备好了。我有了可以根据自身需要随意进行渲染的 Direct2D 设备。现在,我需要将此渲染设备告诉 Windows 组合引擎。这正是那些掩蔽的接口进入的地方。对于我自始至终都在使用的排序器,我可以查询 ICompositorInterop 接口:
~~~
namespace abi = ABI::Windows::UI::Composition;
ComPtr<abi::ICompositorInterop> compositorInterop;
check(compositor->QueryInterface(set(compositorInterop)));
~~~
ICompositorInterop 提供了从 DXGI 设计面创建组合设计面的方法(如果您想要在组合可视化树中包含现有交换链,这绝对方便),但是它还提供了一些更有趣的别的方法。其 CreateGraphicsDevice 方法将创建一个给出渲染设备的 CompositionGraphicsDevice 对象。CompositionGraphicsDevice 类是 Windows 组合 API 中的一个常规类,而不是掩蔽的接口,但是它未提供构造函数,因此您需要使用 C++ 和 ICompositorInterop 接口来创建它:
~~~
CompositionGraphicsDevice device = nullptr;
check(compositorInterop->CreateGraphicsDevice(get(direct2dDevice), set(device)));
~~~
由于 CompositionGraphicsDevice 是 WinRT 类型,因此我可以再次使用现代 C++,而非借助指针以及手动错误处理。而且是 CompositionGraphicsDevice 最终允许我创建组合设计面的:
~~~
using namespace Windows::Graphics::DirectX;
CompositionDrawingSurface surface =
compositionDevice.CreateDrawingSurface(Size{ 100, 100 },
DirectXPixelFormat::B8G8R8A8UIntNormalized,
CompositionAlphaMode::Premultiplied);
~~~
在此,我将创建一个大小为 100 x 100 像素的设计面。注意,这表示实际像素,而非其余 Windows 组合假设并提供的逻辑和 DPI 感知坐标。该设计面还提供了 Direct2D 支持的 32 位 alpha 混合渲染。当然,Direct3D 和 Direct2D 尚未通过 Windows 运行时提供,因此又回到掩蔽的接口来实际绘制到此设计面:
~~~
ComPtr<abi::ICompositionDrawingSurfaceInterop> surfaceInterop;
check(surface->QueryInterface(set(surfaceInterop)));
~~~
Windows 组合很像在它之前的 DirectComposition,它在 ICompositionDrawingSurfaceInterop 接口上提供 BeginDraw 和 EndDraw 方法,这些方法将纳入典型调用并将典型方法替代为通过相同名称执行的 Direct2D 方法调用:
~~~
ComPtr<ID2D1DeviceContext> dc;
POINT offset = {};
check(surfaceInterop->BeginDraw(nullptr, // Update rect
__uuidof(dc),
reinterpret_cast<void **>(set(dc)),
&offset));
~~~
Windows 组合获取在创建组合设备时提供的原始渲染设备,并使用它创建设备上下文或渲染目标。我可以选择以物理像素提供一个剪切矩形,但是在此我只选择对渲染设计面进行不受限访问。BeginDraw 也会再次返回一个以物理像素计算的偏移,以表明预期的绘图表面的由来。这并不一定是渲染目标的左上角,必须要小心地调整或转换任何绘图命令使他们正确地接纳此偏移。同样,不要在渲染目标上调用 BeginDraw,因为 Windows 组合已经为您执行该操作。该渲染目标逻辑上由组合 API 拥有,必须小心谨慎,不要在调用 EndDraw 后按住它。渲染目标现已准备好,但不了解视图的逻辑或有效 DPI。我可以使用 Windows::Graphics::Display 命名空间获取当前视图的逻辑 DPI 并设置 Direct2D 将用于进行渲染的 DPI:
~~~
using namespace Windows::Graphics::Display;
DisplayInformation display = DisplayInformation::GetForCurrentView();
float const dpi = display.LogicalDpi();
dc->SetDpi(dpi, dpi);
~~~
开始渲染之前的最后一步是,通过某种方法处理组合偏移。一个简单的解决办法就是使用偏移制作转换矩阵。不过记住,Direct2D 以逻辑像素计算,所以我不仅需要使用偏移,还需要使用新确立的 DPI 值:
~~~
dc->SetTransform(D2D1::Matrix3x2F::Translation(offset.x * 96.0f / dpi,
offset.y * 96.0f / dpi));
~~~
此时,在设计面的 interop 接口上调用 EndDraw 方法之前,您可以尽情地绘制,以确保所有成批的 Direct2D 绘制命令得到处理,且对设计面所做的更改也反映在组合可视化树中:
~~~
check(surfaceInterop->EndDraw());
~~~
当然,我尚未将设计面与视觉对象关联,并且正如我所提到的,视觉对象不再提供内容属性,且必须使用画笔渲染。庆幸的是,排序器将创建一个画笔来表示预先存在的设计面:
~~~
CompositionSurfaceBrush brush = compositor.CreateSurfaceBrush(surface);
~~~
然后,我可以创建一个常规的子画面画笔,并使用此画笔让视觉对象发光:
~~~
SpriteVisual visual = compositor.CreateSpriteVisual();
visual.Brush(brush);
visual.Size(Vector2{ ... });
~~~
如果这样的互操作性对于您来说不够,您甚至可以采用 XAML 元素并检索基础组合视觉对象。下面是使用 C# 的一个例子:
~~~
using Windows.UI.Xaml.Hosting;
Visual visual = ElementCompositionPreview.GetElementVisual(button);
~~~
尽管 ElementCompositionPreview 看起来像是临时的状态,而事实上它已做好制作准备,可被已提交到 Windows 应用商店的应用使用。对于任意 UI 元素,静态 GetElementVisual 方法将从基础组合可视化树中返回视觉对象。注意,它返回 Visual,而非 ContainerVisual 或 SpriteVisual,因此您不能直接使用视觉对象子项或应用画笔,但是您可以调整 Windows 组合提供的许多视觉对象属性。ElementCompositionPreview 帮助程序类提供了一些其他的静态方法,用于以控制的方式添加子视觉对象。您可以更改视觉对象的偏移,以及类似于将继续在 XAML 级别运行的 UI 点击测试这样的功能。您甚至可以直接使用 Windows 组合应用动画,而不用破坏构建于其上的 XAML 基础架构。让我们创建一个简单的标量动画来旋转按钮。我需要从视觉对象中检索排序器,然后像以前一样创建一个动画对象:
~~~
Compositor compositor = visual.Compositor;
ScalarKeyFrameAnimation animation = compositor.CreateScalarKeyFrameAnimation();
~~~
让我们构建一个简单的动画来始终使用线性缓动函数缓慢旋转按钮:
~~~
animation.InsertKeyFrame(1.0f, (float) (2 * Math.PI),
compositor.CreateLinearEasingFunction());
~~~
然后,我可以指明一次旋转花费 3 秒并一直继续:
~~~
animation.Duration = TimeSpan.FromSeconds(3);
animation.IterationBehavior = AnimationIterationBehavior.Forever;
~~~
最后,我可以简单地将动画连接到 XAML 提供的视觉对象,指示组合引擎对其 RotationAngle 属性制作动画:
~~~
visual.StartAnimation("RotationAngle", animation);
~~~
尽管您可能只用 XAML 就能实现这一目标,但 Windows 组合引擎提供了更强大的功能与灵活性,因为它驻留在更低的抽象级别,无疑会提供更出色的性能。再举个例子,Windows 组合提供了 XAML 目前不支持的四元数动画。
关于 Windows 组合引擎还有很多话题可以谈。依我个人浅见,这是迄今最具突破性的 WinRT API。可供您任意使用的功能无比强大,而且,与很多其他大型 UI 和图形 API 不同,它不会影响性能,甚至不会占用您太多学习时间。在许多方面,Windows 组合都展现出 Windows 平台的美妙与震撼。
您可以在 Twitter [@WinComposition](https://twitter.com/@WinComposition) 找到 Windows Composition 团队。
* * *
Kenny Kerr *是加拿大的计算机程序员,是 Pluralsight 的作者,也是一名 Microsoft MVP。他的博客网址是 [kennykerr.ca](http://kennykerr.ca/),您可以通过 Twitter [@kennykerr](https://twitter.com/@kennykerr) 关注他。*
Microsoft .NET – .NET 和通用 Windows 平台开发
最后更新于:2022-04-01 06:55:30
* * *
WINDOWS 10 2015 年特别版
# Microsoft .NET - .NET 和通用 Windows 平台开发
作者 [Daniel Jacobson](https://msdn.microsoft.com/zh-cn/magazine/mt149362?author=Daniel+Jacobson) | Windows 2015
借助 Visual Studio 2015,您现在可以使用最新 .NET 技术构建运行于所有 Windows 10 设备(其中包括您口袋里的手机、背包中的笔记本电脑或平板电脑、办公室里的 Surface Hub、家里的 Xbox 控制台、HoloLens 以及您可以想象的任何其他物联网 (IoT) 设备)上的通用 Windows 平台 (UWP) 应用程序。成为 Windows 开发人员真的是太让人激动了。
## UWP 的新增功能
作为一名 .NET 开发人员,您将会对 UWP 提供的所有功能欣喜若狂。UWP 应用将在大量已经且将继续升级至 Windows 10 的桌面上以“窗口化”模式运行。UWP 应用将能够通过一个应用程序包和一个代码库连接所有 Windows 10 设备。此外,UWP 应用还充分利用全新 Microsoft .NET Core Framework(本文后面部分有详细介绍)。您的 .NET 业务逻辑可以运行于支持 .NET Core 的其他平台,例如 ASP.NET 5。UWP 应用为应用部署一小块 .NET Core,这样应用将始终针对您测试应用所依据的 .NET 版本运行。所有 .NET UWP 应用都充分利用 .NET Native,其可生成高度优化的本机代码,从而提升性能(本文也有所介绍)。
## .NET Core Framework
.NET Core Framework 是适用于现代设备和云工作负载的新版 .NET。它是 Microsoft .NET Framework 的通用及模块化实现,可以针对各种工作负载在许多不同的环境中移植和使用。此外,.NET Core Framework 是开源代码并在 GitHub ([github.com/dotnet/corefx](http://github.com/dotnet/corefx)) 上提供,Microsoft 在 Windows、Linux 和 Mac OS X 上均提供支持。如果您是使用最新 .NET 技术的 UWP 开发人员,这对您来说将是非常大的优势。在 Visual Studio 2015 中,您可以利用 .NET Core 可移植类库 (PCL) 来锁定任意 UWP 应用、.NET 4.6 应用或 ASP.NET 5 应用(甚至那些跨平台应用)。
此外,.NET Core Framework 还是先前在 Windows 应用商店应用开发中可用的 .NET API 的超集。这就表示,UWP 开发人员现在在其 API 库中拥有其他多个命名空间。其中一个此类命名空间是 System.Net.Sockets,用于 UDP 通信。这之前在 Windows Runtime (WinRT) 应用中不可用,解决方法是使用 WinRT 特定 UDP API。由于套接字在 .NET Core 中可用,因此,您可以在 UWP 应用及其他 .NET 应用中使用相同的套接字代码。
另一大优势是,System.Net.Http.HttpClient API 构建于 WinRT HTTP 堆栈之上。这样,如果服务器支持 HTTP/2,默认情况下就可以使用它,从而降低延迟并减少来回通信。
Windows Communication Foundation (WCF) 客户端(以及关联的“添加服务引用”对话框)先前在 Windows Phone .appx 项目中不可用,但是因为它属于 .NET Core,所以可以由所有 .NET UWP 应用使用。
最后,.NET Core 是 .NET Native 依赖的基础框架。设计 .NET Native 时,很显然 .NET Framework 将不适合作为框架类库的基础。这是因为 .NET Native 静态地将框架与应用相连,然后删除应用不需要的额外内容。(这是粗略简单的介绍,但是您已经明白了。有关更多详细信息,请查看“Inside .NET Native”(.NET Native 内部),网址为 [bit.ly/1UR7ChW](http://bit.ly/1UR7ChW)。)
由于未构造传统的 .NET Framework 实现,因此,对于链接器而言,减少编译到应用中的框架量是个挑战。毕竟,.NET Core 实际上是 .NET Framework 的分支,而 .NET Framework 的实现已围绕构造问题进行了优化。该实现的另一个优势是能够将 .NET Core Framework 作为一套 NuGet 程序包进行交付,这样就可以从 .NET Framework 带外更新各个类。不过,在进一步操作之前,让我们来看看 NuGet 中的一些变化。
## NuGet 的新增功能
对于 UWP,已内置 NuGet 3.1 支持。此版本中包括可改进程序包依赖项管理以及本地缓存程序包以便在多个项目中重用的功能。
对于 NuGet 3.1,程序包依赖项声明模型已更新。从 ASP.NET 5 开始,NuGet 引入了对 project.json 文件的支持,这是 UWP 支持的同一模型。Project.json 使您可以介绍一个项目的依赖项,清晰地定义您直接依赖的程序包。由于对于 ASP.NET 5 和 UWP 而言格式相同,因此您可以使用相同的文件定义两个平台以及 PCL 的程序包引用。
从 packages.config 更改为 project.json 使您可以在项目中“重新启动”应用,而且现在有了新的 NuGet 传递依赖项功能。如果您引用一个引用了另一 NuGet 程序包的程序包,则使用它管理包版本会比较困难。例如,NHibernate 是依赖于 lesi.Collections 的程序包。在 packages.config 中,您将会有两个引用,每个程序包一个引用。想要更新 NHibernate 时,是否也会更新 lesi.collections? 如果有适用于 lesi.collections 的更新,是否还需要更新 NHibernate 来支持新功能? 这会变成混乱的循环,程序包版本管理比较困难。NuGet 的可传递依赖项功能简化了这一决定,通过程序包定义文件 (nuspecs) 中改进的语义版本更新程序包引用。
此外,NuGet 现在可下载您使用的程序包副本并将这些程序包的副本存储在位于 %userprofile%\.nuget\packages 文件夹中的全局程序包文件夹中。这不仅可以提升程序包引用的性能(因为您将只需下载每个程序包一次),而且还会减少您工作站上所用的磁盘空间(因为您可以在项目间共享相同的程序包二进制文件)。
## NuGet 和 .NET Core
使用注重构造的 .NET Core 并将其与 NuGet 3.1 的程序包依赖项管理结合时会如何? 您将可以从 .NET Framework 的其余部分带外更新各个 .NET Framework 程序包。对于 UWP,.NET Core 作为一套 NuGet 程序包包含在您的应用中。创建新项目时,您将只看到常规 Microsoft.NETCore.UniversalWindowsPlatform 程序包依赖项,但是如果在 NuGet 上看到此程序包,您将会看到包含的所有 .NET Framework 库,如图 1 所示。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-08_568f406da9da6.png)
图 1 查看 NuGet 中的 .NET Framework 库
例如,假设存在引入您喜欢在应用程序中使用的新 API 的 System.Net.Sockets 类的更新。对于传统的 .NET,您的应用需要依赖于整个 .NET Framework 的新版本。对于 UWP 和具有 NuGet 的 .NET Core,您可以将 NuGet 依赖项更新为包含该程序包的最新版本即可。然后,编译和打包您的应用程序时,该版本的框架库将包含在您的应用程序中。这样一来,您便可以灵活地使用最新且最强大的 .NET 技术,而不用迫使用户始终在其设备上安装最新的框架。
除了能够根据您自己的节奏更新 .NET 类之外,.NET Core 的组件化特征还能使 .NET Native 在交付到用户设备时为所有 Windows 10 C# 和 Visual Basic 应用程序带来性能优势。
## 什么是 .NET Native?
现在,您已经了解 .NET Core Framework 实现了 .NET Native,接下来我将为您详细介绍什么是 .NET Native 及其可为 UWP 开发人员提供哪些功能。
.NET Native 是一种预先 (AOT) 编译过程,其在编译时将您的托管 .NET 代码转变为本机代码。相反,传统的 .NET 则采用实时 (JIT) 编译,这会延迟方法的本机编译,直到其在运行时首次执行。.NET Native 更类似于 C++ 编译器。事实上,它采用 Visual Studio C++ 编译器作为其工具链的一部分。每个托管的(C# 或 Visual Basic)通用 Windows 应用都将利用这一新技术。应用程序会在到达用户设备之前自动编译为本机代码。如果您想深入了解其工作原理,我强烈建议您阅读 MSDN 库文章“Compiling Apps with .NET Native”(使用 .NET Native 编译应用),网址为 [bit.ly/1QcTGxm](http://bit.ly/1QcTGxm)。
## .NET Native 为您及您的应用带来哪些影响?
获得的好处可能不尽相同,但是大多数情况下,应用启动速度会变快、性能会更出色且占用的系统资源会更少。预计首次启动应用程序时其性能会提升 60%,后续启动(“热”启动)则会实现高达 40% 的性能提升。进行本机编译时,应用程序会占用更少的内存。.NET 运行时的所有依赖项都会被删除,所以最终用户将永不需要跳出安装体验过程即可获得您应用所引用的特定 .NET Framework 版本。事实上,所有 .NET 依赖项均打包在您的应用程序内,所以您应用的行为不会因计算机上安装的 .NET Framework 有变化而发生变化。
即使您的应用程序正编译为本机二进制文件,您仍可利用您熟悉的 .NET 语言(C# 或 Visual Basic)以及关联的出色工具。最后,您可以继续使用 .NET Framework 提供的全面且一致的编程模型,它具有面向业务逻辑、内置内存管理以及异常处理的广泛 API。
有了 .NET Native,您在以下两个方面均实现最优化:托管的开发和 C++ 性能。这多酷啊!
## 调试与发布编译配置
.NET Native 编译是一个复杂的过程,这就使得其比经典 .NET 编译要慢一点。前面提到的优势都是以牺牲编译时间为代价的。每次要运行应用时您都可以选择本机编译,但是您将会花费额外的时间来等待生成完成。Visual Studio 工具旨在解决这一问题,以及打造尽可能顺畅的开发体验。
在“调试”配置中构建并运行时,您将针对应用程序内打包的 CoreCLR 运行中间语言代码。.NET 系统组件与您的应用程序代码一起打包,您的应用程序将依赖于 Microsoft.NET.CoreRuntime (CoreCLR) 程序包。如果您正在测试的设备缺少 CoreCLR 框架,则在部署您的应用程序之前,Visual Studio 将自动检测并进行安装。
这意味着您可以获得尽可能出色的开发体验:快速编译和部署、丰富的调试与诊断以及您习惯用于 .NET 开发的所有工具。
切换至“发布”模式时,默认情况下,您的应用会利用 .NET Native 工具链。因为程序包编译到本机二进制文件,所以程序包不需要包含 .NET Framework 库。而且,程序包依赖于最新安装的 .NET Native 运行时(与 CoreCLR 程序包相反)。设备上的 .NET Native 运行时将始终与您的应用程序包兼容。
通过“发布”配置进行的本地本机编译将支持在与您客户将体验的环境类似的一种环境中测试您的应用程序。要继续进行开发,定期进行该测试非常重要! 通过使用您的客户将体验的代码生成和运行时技术测试您的应用程序,您将可以确保解决所有可能的 bug(例如由于不同性能特点导致的潜在争用条件)。
一个很好的经验法则就是,在开发过程中定期对您的应用进行这一测试,以确保发现并纠正 .NET Native 编译器可能会导致的任何问题。大多数情况下,不会有问题;但是,仍会有一些与 .NET Native 不太兼容的条目。4+ 维数组就是个例子。最终,您的客户将会获得您的应用程序的 .NET Native 编译版本,所以在开发过程中以及发运之前对该版本进行测试始终是个好的做法。
除了测试 .NET Native 编译,您可能还会注意到 AnyCPU 生成配置消失了。有了 .NET Native,AnyCPU 不再是有效的生成配置,因为本机编译依赖体系结构。另一个结果就是,在您打包应用程序时,应选择全部三个体系结构配置(x86、x64 和 ARM)以确保您的应用程序尽可能适用于更多的设备。这毕竟是通用 Windows 平台。
这么说来,您仍可以构建要在您的 UWP 应用中引用的 AnyCPU 库和 DLL。这些组件将基于使用它的项目 (.appx) 的配置编译到特定于体系结构的二进制文件中。
## 云中的 .NET Native
.NET Native 一个强大的功能就是编译器可以托管在云中。这意味着,当对编译器进行可能会对您的应用程序产生有益影响的改进后,应用商店的云托管 .NET Native 编译器可以重新编译您的应用程序包来获取这些优势。每次完成此编译后,对于您这个开发人员都将是透明的,但是,最终都是应用程序用户更幸福。
不过,这会对您的工作流程产生一些影响。例如,确保您始终安装最新的工具是很好的想法,这样您就可以针对最新本地版本的编译器测试您的 .NET Native 编译。此外,在 Visual Studio 中构建您的应用商店程序包时,会创建两个程序包:一个是 .appxupload,一个是 “test”.appx,用于旁加载。.appxupload 包含 MSIL 二进制文件,以及对您应用使用的 .NET Native 工具链版本的显式引用(在 AppxManifest.xml 中引用为“ilc.exe”)。之后,该程序包进入应用商店并使用相同的 .NET Native 工具链版本对其进行编译。因为编译器是云托管编译器,所以它可以循环修复 bug,而不用您本地重新编译应用。
使用 .NET Native 时,您必须谨慎对待上传至应用商店的程序包。因为应用商店为您执行本机编译,所以您不能上传本地 .NET Native 编译器生成的本机二进制文件。Visual Studio 工作流将指导您完成该过程,以便您选择正确的程序包。有关创建应用商店程序包的全面指导,请查看 MSDN 库文章“Packaging Universal Windows Apps for Windows 10”(打包 Windows 10 的通用 Windows 应用),网址为 [bit.ly/1OQTTG0](http://bit.ly/1OQTTG0)。该文章将指导您完成程序包创建过程,以确保您生成并选择要上传至商店的正确程序包。
## 使用 .NET Native 调试
如果您发现应用程序中某些问题可能是由 .NET Native 所导致,您可以使用一项技术来帮助调试该问题。默认情况下,发布配置全面优化代码(例如,在很多地方应用的代码内联),这会丢失一些调试项目。因此,尝试调试发布配置应用会很困难;您可能会遇到预料不到的步进和断点行为,并且由于内存优化而无法检查变量。因为发布配置的默认行为是使用代码优化的 .NET Native 编译器,所以很难调试可能是由 .NET Native 编译过程导致的任何问题。
一个很好的解决办法是,为采用 .NET Native 编译器但未全面优化代码的项目创建自定义生成配置。要创建自定义生成配置,请从版本配置下拉菜单中打开“配置服务器”,如图 2 所示。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-08_568f406db9fd9.png)
图 2 打开配置服务器
在“活动”解决方案配置下拉菜单中,选择“”创建新配置,如图 3 所示。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-08_568f406dcc498.png)
图 3 新建配置
为新配置提供日后对您有用的名称。我想使用“Debug .NET Native”。 从“发布”生成配置中复制设置,然后单击“确定”。
关闭配置管理器,通过右键单击解决方案资源管理器中的项目并单击“属性”来打开项目的属性页。导航到“生成”选项卡并确保选中“使用 .NET Native 工具链编译”,而且取消选中“优化代码”,如图 4 所示。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-08_568f406ddec2e.png)
图 4 为调试 .NET Native 创建生成配置
现在,您拥有可用于调试 .NET Native 特定问题的生成配置。
有关使用 .NET Native 进行调试的详细信息,请参阅 MSDN 库文章“Debugging .NET Native Windows Universal Apps”(调试 .NET Native Windows 通用应用),网址为 [bit.ly/1Ixd07v](http://bit.ly/1Ixd07v)。
## .NET Native Analyzer
当然,了解如何调试问题挺好的,但是能从一开始就避免问题岂不是更好? Microsoft.NETNative.Analyzer ([bit.ly/1LugGnO](http://bit.ly/1LugGnO)) 可以通过 NuGet 在您的应用程序中安装。通过程序包管理器控制台,您可以使用下列命令安装程序包: Install-Package Microsoft.NETNative.Analyzer。开发时,如果您的代码与 .NET Native 编译器不兼容,该分析器将会为您发出警告。有一小部分 .NET 接口不兼容,但是对于大多数应用而言,这根本不是问题。
## 结束语
综上所述,成为 .NET Windows 开发人员是多么令人激动的事情啊!凭借 UWP、.NET Native 以及对 NuGet 的更改,跨这么多客户喜爱的不同设备创建应用从未如此简单。您将有史以来第一次可以充分利用任何 .NET 类的最新进步,并且依然期望您的应用程序能够在所有 Windows 10 设备上运行。
* * *
Daniel Jacobson *是 Visual Studio 的程序管理员,致力于研究面向 Windows 平台开发人员的工具。您可以通过 [dajaco@microsoft.com](mailto:dajaco@microsoft.com) 与他联系。*
介绍
最后更新于:2022-04-01 06:55:28
原文出处:https://msdn.microsoft.com/zh-cn/magazine/win10issue.aspx
# MSDN 特刊 2015
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-08_568f406c1d7eb.jpg)