将 Windows 运行时 8.x 项目移植到 UWP 项目Porting a Windows Runtime 8.x project to a UWP project

在开始移植过程时,你有两个选择。You have two options when you begin the porting process. 一是编辑现有项目文件的副本,包括应用包清单(对于该选项,请参阅将应用迁移到通用 Windows 平台应用 (UWP) 中有关更新项目文件的信息)。One is to edit a copy of your existing project files, including the app package manifest (for that option, see the info about updating your project files in Migrate apps to the Universal Windows Platform (UWP)). 另一个是在 Visual Studio 中创建一个新的 Windows 10 项目,并将你的文件复制到其中。The other option is to create a new Windows 10 project in Visual Studio and copy your files into it. 本主题的第一部分描述了第二个选择,但本主题的其余部分提供了同时适用于这两个选择的其他信息。The first section in this topic describes that second option, but the rest of the topic has additional info applicable to both options. 你还可以选择将新的 Windows 10 项目保留在与你的现有项目相同的解决方案中,并使用已共享的项目共享源代码文件。You can also choose to keep your new Windows 10 project in the same solution as your existing projects and share source code files using a shared project. 或者,你也可以将新项目保留在它自己的解决方案中,并使用 Visual Studio 中链接的文件功能共享源代码文件。Or, you can keep the new project in a solution of its own and share source code files using the linked files feature in Visual Studio.

创建项目并将文件复制到其中Create the project and copy files to it

这些步骤侧重于以下内容:在 Visual Studio 中创建一个新的 Windows 10 项目,并将你的文件复制到其中。These steps focus on the option to create a new Windows 10 project in Visual Studio and copy your files into it. 某些围绕着所创建的项目数和要复制的文件展开的特定步骤,将依赖于如果你有一个通用 8.1 应用及其后的部分中所述的规格和决策。Some of the specifics around how many projects you create, and which files you copy over, will depend on the factors and decisions described in If you have a Universal 8.1 app and the sections that follow it. 这些步骤中假设了最简单的应用场景。These steps assume the simplest case.

  1. 启动 Microsoft Visual Studio 2015 并创建新的空白应用程序(Windows 通用)项目。Launch Microsoft Visual Studio 2015 and create a new Blank Application (Windows Universal) project. 有关详细信息,请参阅 使用 (c #、c + +、Visual Basic) 中的模板快速启动 Windows 运行时3.x 应用。For more info, see Jumpstart your Windows Runtime 8.x app using templates (C#, C++, Visual Basic). 你的新项目会生成一个将在所有设备系列上运行的应用包(appx 文件)。Your new project builds an app package (an appx file) that will run on all device families.
  2. 在 Universal 8.1 App 项目中,标识要重用的所有源代码文件和视觉资产文件。In your Universal 8.1 app project, identify all the source code files and visual asset files that you want to reuse. 通过使用文件资源管理器,将数据模型、视图模型、视觉资源、资源词典,文件夹结构和想要重复使用的任何其他内容复制到新项目中。Using File Explorer, copy data models, view models, visual assets, Resource Dictionaries, folder structure, and anything else that you wish to re-use, to your new project. 根据需要在磁盘上复制或创建子文件夹。Copy or create sub-folders on disk as necessary.
  3. 还可以将视图(例如,MainPage.xaml 和 MainPage.xaml.cs)复制到新项目中。Copy views (for example, MainPage.xaml and MainPage.xaml.cs) into the new project, too. 同样,也可根据需要创建新的子文件夹,并从项目中删除现有视图。Again, create new sub-folders as necessary, and remove the existing views from the project. 但是,在覆盖或删除 Visual Studio 生成的视图之前,请保留一份副本,因为在以后引用它时,这可能会很有用。But, before you over-write or remove a view that Visual Studio generated, keep a copy because it may be useful to refer to it later. 移植通用 8.1 应用的第一个阶段侧重于使其在某一设备系列上正常显示并良好运行。The first phase of porting a Universal 8.1 app focuses on getting it to look good and work well on one device family. 之后,将侧重点转到确保视图能自行适应所有外形规格,也可以选择添加任何自适应代码以最大程度地利用特定的设备系列。Later, you'll turn your attention to making sure the views adapt themselves well to all form factors, and optionally to adding any adaptive code to get the most from a particular device family.
  4. “解决方案资源管理器” 中,请确保将 “显示所有文件” 切换为打开。In Solution Explorer, make sure Show All Files is toggled on. 选择要复制的文件,右键单击这些文件,然后单击包括在项目中Select the files that you copied, right-click them, and click Include In Project. 这将自动包括其所包含的文件夹。This will automatically include their containing folders. 然后,可根据需要将 “显示所有文件” 切换为关闭。You can then toggle Show All Files off if you like. 备用工作流(如果选择)旨在使用 “添加现有项” 命令,以便在 Visual Studio “解决方案资源管理器” 中创建任何必要子文件夹。An alternative workflow, if you prefer, is to use the Add Existing Item command, having created any necessary sub-folders in the Visual Studio Solution Explorer. 仔细检查可见资源是否已将生成操作设置为内容,并将复制到输出目录设置为不复制Double-check that your visual assets have Build Action set to Content and Copy to Output Directory set to Do not copy.
  5. 你很可能会在此阶段看到一些生成错误。You are likely to see some build errors at this stage. 不过,如果你知道需要更改哪些内容,则可以使用 Visual Studio 的 Find and Replace 命令批量更改源代码;并且可以在 Visual Studio 的强制性代码编辑器中,使用上下文菜单上的 ResolveOrganize Usings 命令了解更多目标更改。But, if you know what you need to change, then you can use Visual Studio's Find and Replace command to make bulk changes to your source code; and in the imperative code editor in Visual Studio, use the Resolve and Organize Usings commands on the context menu for more targeted changes.

最大程度地重新使用标记和代码Maximizing markup and code reuse

你会发现,只需稍作重构和/或添加自适应代码(将在下文进行介绍),即可最大程度地重新使用可跨所有设备系列运行的标记和代码。You will find that refactoring a little, and/or adding adaptive code (which is explained below), will allow you to maximize the markup and code that works across all device families. 下面提供了更多详细信息。Here are more details.

  • 无需特别考虑在所有设备系列上均通用的文件。Files that are common to all device families need no special consideration. 这些文件将由可在所有设备系列上运行的应用使用。Those files will be used by the app on all the device families that it runs on. 这包括 XAML 标记文件、强制性源代码文件和资产文件。This includes XAML markup files, imperative source code files, and asset files.
  • 你的应用既能检测到正在运行它的设备系列,又能导航到专门为该设备系列设计的视图。It is possible for your app to detect the device family that it is running on and navigate to a view that has been designed specifically for that device family. 有关详细信息,请参阅检测应用所运行的平台For more details, see Detecting the platform your app is running on.
  • 在以下情况中,你可能会发现一种类似的技术也许会很有用:必须要为某个标记文件或 ResourceDictionary 文件(或者包含该文件的文件夹)提供一个特殊名称,以便它仅当应用在特定设备系列上运行时才自动在运行时加载。A similar technique that you may find useful if there is no alternative is give a markup file or ResourceDictionary file (or the folder that contains the file) a special name such that it is automatically loaded at runtime only when your app runs on a particular device family. 此技术将在 Bookstore1 案例研究中进行介绍。This technique is illustrated in the Bookstore1 case study.
  • 如果你仅需要支持 Windows 10,你应该能够删除通用 8.1 应用源代码中的大量条件编译指令。You should be able to remove a lot of the conditional compilation directives in your Universal 8.1 app's source code if you only need to support Windows 10. 请参阅本主题中的条件编译和自适应代码See Conditional compilation and adaptive code in this topic.
  • 若要使用未在所有设备系列上提供的功能(例如打印机、扫描仪或相机按钮),你可以编写自适应代码。To use features that are not available on all device families (for example, printers, scanners, or the camera button), you can write adaptive code. 请参阅本主题下条件编译和自适应代码中的第三个示例。See the third example in Conditional compilation and adaptive code in this topic.
  • 如果你想要同时支持 Windows 8.1、Windows Phone 8.1 和 Windows 10,你可以将三个项目都保留在同一个解决方案中并与共享的项目共享代码。If you want to support Windows 8.1, Windows Phone 8.1, and Windows 10, then you can keep three projects in the same solution and share code with a Shared project. 此外,你可以在项目之间共享源代码文件。Alternatively, you can share source code files between projects. 具体操作方式:在 Visual Studio 中,右键单击 解决方案资源管理器的项目,选择 " 添加现有项",选择要共享的文件,然后单击 " 添加为链接"。Here's how: in Visual Studio, right-click the project in Solution Explorer, select Add Existing Item, select the files to share, and then click Add As Link. 将源代码文件存储在文件系统上的常用文件夹中,可在指向它们的链接所在的项目中看到这些文件。Store your source code files in a common folder on the file system where the projects that link to them can see them. 不要忘记将它们添加到源控件中。And don't forget to add them to source control.
  • 若要在二进制级别(而不是源代码级别)重新使用,请参阅使用 c # 和 Visual Basic 创建 Windows 运行时组件For reuse at the binary level, rather than the source code level, see Creating Windows Runtime components in C# and Visual Basic. 还存在一些可移植类库,这些库支持在适用于 Windows 8.1、Windows Phone 8.1 和 Windows 10 应用 (.NET Core) 的 .NET Framework 以及整个 .NET Framework 中可用的 .NET API 子集。There are also Portable Class Libraries, which support the subset of .NET APIs that are available in the .NET Framework for Windows 8.1, Windows Phone 8.1, and Windows 10 apps (.NET Core), and the full .NET Framework. 可移植类库程序集为二进制形式,可与所有这些平台兼容。Portable Class Library assemblies are binary compatible with all these platforms. 使用 Visual Studio 创建一个面向可移植类库的项目。Use Visual Studio to create a project that targets a Portable Class Library. 请参阅使用可移植类库的跨平台开发See Cross-Platform Development with the Portable Class Library.

扩展 SDKExtension SDKs

大多数已由通用 8.1 应用调用的 Windows 运行时 API 都在所谓的通用设备系列的 API 集中实现。Most of the Windows Runtime APIs your Universal 8.1 app already calls are implemented in the set of APIs known as the universal device family. 但是,部分 API 在扩展 SDK 中实现,因为 Visual Studio 只能识别由你的应用的目标设备系列或所引用的任何扩展 SDK 实现的 API。But, some are implemented in extension SDKs, and Visual Studio only recognizes APIs that are implemented by your app's target device family or by any extension SDKs that you have referenced.

如果你收到有关找不到命名空间、类型或成员的编译错误,这很可能是导致此类错误出现的原因。If you get compile errors about namespaces or types or members that could not be found, then this is likely to be the cause. 打开 API 参考文档中的 API 主题并导航到“要求”部分:你可以从中了解到设备系列实现的内容。Open the API's topic in the API reference documentation and navigate to the Requirements section: that will tell you what the implementing device family is. 如果这不是你的目标设备系列,但需要使相应 API 适用于你的项目,你将需要一个对该设备系列的扩展 SDK 的引用。If that's not your target device family, then to make the API available to your project, you will need a reference to the extension SDK for that device family.

单击 " 项目" " > 添加引用" " > Windows 通用 > 扩展 ",然后选择相应的扩展 SDK。Click Project > Add Reference > Windows Universal > Extensions and select the appropriate extension SDK. 例如,如果你想要调用的 Api 仅在移动设备家族中提供,并且在版本 10.0. x. x. x. x 中引入,则选择 "适用于 UWP 的 Windows Mobile 扩展"For example, if the APIs you want to call are available only in the mobile device family, and they were introduced in version 10.0.x.y, then select Windows Mobile Extensions for the UWP.

这将向你的项目文件添加以下引用:That will add the following reference to your project file:

<ItemGroup>
    <SDKReference Include="WindowsMobile, Version=10.0.x.y">
        <Name>Windows Mobile Extensions for the UWP</Name>
    </SDKReference>
</ItemGroup>

名称和版本号需与 SDK 的安装位置所在的文件夹匹配。The name and version number match the folders in the installed location of your SDK. 例如,上述信息需与以下文件夹名称匹配:For example, the above information matches this folder name:

\Program Files (x86)\Windows Kits\10\Extension SDKs\WindowsMobile\10.0.x.y

除非你的应用面向可实现此 API 的设备系列,否则你将需要先使用 ApiInformation 类测试该 API 是否存在,然后才能调用它(这称为自适应代码)。Unless your app targets the device family that implements the API, you'll need to use the ApiInformation class to test for the presence of the API before you call it (this is called adaptive code). 然后,评估此条件(无论你的应用在何处运行),但其仅针对存在相应 API 的设备才评估为 True,从而可调用该 API。This condition will then be evaluated wherever your app runs, but it will only evaluate to true on devices where the API is present and therefore available to call. 仅在首次检查是否存在通用 API 后,才能使用扩展 SDK 和自适应代码。Only use extension SDKs and adaptive code after first checking whether a universal API exists. 下面的部分中提供了一些示例。Some examples are given in the section below.

另请参阅应用包清单Also, see App package manifest.

条件编译和自适应代码Conditional compilation and adaptive code

如果你为了让代码文件能同时在 Windows 8.1 和 Windows Phone 8.1 上运行而(借助 C# 预处理器指令)使用条件编译,你现在可以根据 Windows 10 中已完成的融合工作查看该条件编译。If you're using conditional compilation (with C# preprocessor directives) so that your code files work on both Windows 8.1 and Windows Phone 8.1, then you can now review that conditional compilation in light of the convergence work done in Windows 10. 融合意味着在 Windows 10 应用中,某些条件可能已被彻底删除。Convergence means that, in your Windows 10 app, some conditions can be removed altogether. 而其他条件将更改为运行时检查,如下面的示例所示。Others change to run-time checks, as demonstrated in the examples below.

注意   如果要在一个代码文件中支持 Windows 8.1、Windows Phone 8.1 和 Windows 10,则还可以执行此操作。Note   If you want to support Windows 8.1, Windows Phone 8.1, and Windows 10 in a single code file, then you can do that too. 如果你在 "项目属性" 页上的 "Windows 10" 项目中查看,你会看到项目将 WINDOWS _ UAP 定义为条件编译符号。If you look in your Windows 10 project at the project properties pages, you'll see that the project defines WINDOWS_UAP as a conditional compilation symbol. 因此,您可以将它与 WINDOWS _ 应用程序和 windows _ PHONE _ 应用程序结合使用。So, you can use that in combination with WINDOWS_APP and WINDOWS_PHONE_APP. 这些示例将演示有关从通用 8.1 应用删除条件编译并用等效代码针对 Windows 10 应用进行替换的更为简单的案例。These examples show the simpler case of removing the conditional compilation from a Universal 8.1 app and substituting the equivalent code for a Windows 10 app.

第一个示例将演示 PickSingleFileAsync API(仅适用于 Windows 8.1)和 PickSingleFileAndContinue API(仅适用于 Windows Phone 8.1)的使用模式。This first example shows the usage pattern for the PickSingleFileAsync API (which applies only to Windows 8.1) and the PickSingleFileAndContinue API (which applies only to Windows Phone 8.1).

#if WINDOWS_APP
    // Use Windows.Storage.Pickers.FileOpenPicker.PickSingleFileAsync
#else
    // Use Windows.Storage.Pickers.FileOpenPicker.PickSingleFileAndContinue
#endif // WINDOWS_APP

由于 Windows 10 在 PickSingleFileAsync API 上融合,因此可对你的代码作如下简化:Windows 10 converges on the PickSingleFileAsync API, so your code simplifies to this:

    // Use Windows.Storage.Pickers.FileOpenPicker.PickSingleFileAsync

在此示例中,我们将处理硬件后退按钮,但仅在 Windows Phone 上才进行处理。In this example, we handle the hardware back button—but only on Windows Phone.

#if WINDOWS_PHONE_APP
        Windows.Phone.UI.Input.HardwareButtons.BackPressed += this.HardwareButtons_BackPressed;
#endif // WINDOWS_PHONE_APP

...

#if WINDOWS_PHONE_APP
    void HardwareButtons_BackPressed(object sender, Windows.Phone.UI.Input.BackPressedEventArgs e)
    {
        // Handle the event.
    }
#endif // WINDOWS_PHONE_APP

在 Windows 10 中,后退按钮事件是一个通用概念。In Windows 10, the back button event is a universal concept. 已在硬件或软件中实现的后退按钮都将引发 BackRequested 事件(即,为要处理的事件)。Back buttons implemented in hardware or in software will all raise the BackRequested event, so that's the one to handle.

    Windows.UI.Core.SystemNavigationManager.GetForCurrentView().BackRequested +=
        this.ViewModelLocator_BackRequested;

...

private void ViewModelLocator_BackRequested(object sender, Windows.UI.Core.BackRequestedEventArgs e)
{
    // Handle the event.
}

最后一个示例与上一个示例类似。This final example is similar to the previous one. 下面我们将处理硬件相机按钮,但同样仅在已编译到 Windows Phone 应用包的代码中才进行处理。Here, we handle the hardware camera button—but again, only in the code compiled into the Windows Phone app package.

#if WINDOWS_PHONE_APP
    Windows.Phone.UI.Input.HardwareButtons.CameraPressed += this.HardwareButtons_CameraPressed;
#endif // WINDOWS_PHONE_APP

...

#if WINDOWS_PHONE_APP
void HardwareButtons_CameraPressed(object sender, Windows.Phone.UI.Input.CameraEventArgs e)
{
    // Handle the event.
}
#endif // WINDOWS_PHONE_APP

在 Windows 10 中,硬件相机按钮是一个特定于移动设备系列的概念。In Windows 10, the hardware camera button is a concept particular to the mobile device family. 因为某一应用包将在所有设备上运行,所以我们将使用所谓的自适应代码,将编译时条件更改为运行时条件。Because one app package will be running on all devices, we change our compile-time condition into a run-time condition using what is known as adaptive code. 为此,我们将使用 ApiInformation 类在运行时查询是否存在 HardwareButtons 类。To do that, we use the ApiInformation class to query at run-time for the presence of the HardwareButtons class. 由于 HardwareButtons 在移动扩展 SDK 中进行了定义,因此我们需要针对要编译的代码将对该 SDK 的引用添加到我们的项目。HardwareButtons is defined in the mobile extension SDK, so we'll need to add a reference to that SDK to our project for this code to compile. 但需要注意的是,处理程序仅在实现移动扩展 SDK 中定义的类型且属于移动设备系列的设备上执行。Note, though, that the handler will only be executed on a device that implements the types defined in the mobile extension SDK, and that's the mobile device family. 因此,此代码在特意只使用存在的功能方面,原则上与通用 8.1 代码等效,尽管它采用了不同的实现方式。So, this code is morally equivalent to the Universal 8.1 code in that it is careful only to use features that are present, although it achieves that in a different way.

    // 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 +=
            this.HardwareButtons_CameraPressed;
    }

    ...

private void HardwareButtons_CameraPressed(object sender, Windows.Phone.UI.Input.CameraEventArgs e)
{
    // Handle the event.
}

另请参阅检测正运行你的应用的平台Also, see Detecting the platform your app is running on.

应用包清单App package manifest

Windows 10 中的更改内容主题针对 Windows 10 列出了对程序包清单架构参考所做的更改,其中包括已添加、删除和更改的元素。The What's changed in Windows 10 topic lists changes to the package manifest schema reference for Windows 10, including elements that have been added, removed, and changed. 有关该架构中所有元素、属性和类型的参考信息,请参阅元素层次结构For reference info on all elements, attributes, and types in the schema, see Element Hierarchy. 如果你要移植 Windows Phone 应用商店应用,或者你的应用是对 Windows Phone 应用商店应用的更新,请确保 pm:PhoneIdentity 元素与上一个应用的应用清单中的相应项匹配(使用由应用商店分配给应用的相同 GUID)。If you're porting a Windows Phone Store app, or if your app is an update to an app from the Windows Phone Store, ensure that the pm:PhoneIdentity element matches what's in the app manifest of your previous app (use the same GUIDs that were assigned to the app by the Store). 这将确保要升级到 Windows 10 的应用用户将接收您的新应用作为更新而不是重复项。This will ensure that users of your app who are upgrading to Windows 10 will receive your new app as an update, not a duplicate. 请参阅 pm:PhoneIdentity 参考主题以了解更多详细信息。See the pm:PhoneIdentity reference topic for more details.

你的项目中的设置(包括任何扩展 SDK 引用)决定了你的应用可以调用的 API 图面区域。The settings in your project (including any extension SDKs references) determine the API surface area that your app can call. 但是,你的应用包清单决定了你的客户可以从应用商店将你的应用安装在哪些实际的设备集上。But, your app package manifest is what determines the actual set of devices that your customers can install your app onto from the Store. 有关详细信息,请参阅 TargetDeviceFamily 中的相关示例。For more info, see examples in TargetDeviceFamily.

你可以编辑应用包清单以设置各种声明、功能和某些功能所需的其他设置。You can edit the app package manifest to set various declarations, capabilities, and other settings that some features need. 你可以使用 Visual Studio 应用包清单编辑器来编辑它。You can use the Visual Studio app package manifest editor to edit it. 如果 解决方案资源管理器 未显示,请从 " 视图 " 菜单中选择它。If the Solution Explorer is not shown, choose it from the View menu. 双击“Package.appxmanifest”。****Double-click Package.appxmanifest. 此时会打开“清单编辑器”窗口。This opens the manifest editor window. 选择要更改的相应选项卡,然后进行保存。Select the appropriate tab to make changes and then save.

下一主题为疑难解答The next topic is Troubleshooting.