在桌面应用中托管 WinRT XAML 控件(XAML 岛)

从 Windows 10 1903 版开始,可以使用称为“XAML 岛”的功能在非 UWP 桌面应用程序中托管 WinRT XAML 控件。 可以通过此功能来改进现有 WPF、Windows 窗体和 C++ 桌面 (Win32) 应用程序的外观和功能,并使用只能通过 WinRT XAML 控件使用的最新 Windows UI 功能。 这意味着,可以在现有的 WPF、Windows 窗体和 C++ 桌面应用程序中使用 UWP 功能(例如 Windows Ink)和支持 Fluent Design System 的控件。

可以托管派生自 Windows.UI.Xaml.UIElement 的任何 WinRT XAML 控件,其中包括:

  • Windows SDK 或 WinUI 2 库提供的大多数第一方 WinRT XAML 控件(请参阅例外)。
  • 任何自定义 WinRT XAML 控件(例如,包含多个可一起使用的 WinRT XAML 控件的用户控件)。 必须有自定义控件的源代码,才能通过应用程序对其进行编译。

从根本上讲,XAML 岛是使用 WinRT XAML 托管 API 创建的。 此 API 包含 Windows 10 版本 1903 SDK 中引入的几个 Windows 运行时类和 COM 接口。 我们还在 Windows 社区工具包中提供了一组 XAML 岛 .NET 控件,这些控件在内部使用 WinRT XAML 托管 API,并针对 WPF 和 Windows 窗体应用提供了更方便的开发体验。

使用 XAML 岛的方式取决于应用程序类型和要托管的 WinRT XAML 控件类型。

注意

如果有关于 XAML 岛的反馈,请在 Microsoft.Toolkit.Win32 存储库中创建一个新问题,将你的意见留在那里。

要求

XAML 岛具有以下运行时要求:

  • Windows 10 版本 1903 或更高版本。
  • 如果你的应用程序未打包到 MSIX 包中用于部署,则必须在计算机上安装 Visual C++ 运行时

WPF 和 Windows 窗体应用程序

注意

目前仅支持在面向 .NET Core 3.x 的应用中使用 XAML 岛托管 WPF 和 Windows 窗体应用中的 WinRT XAML 控件。 尚不支持在面向 .NET 的应用中和面向任何 .NET Framework 版本的应用中使用 XAML 岛。

我们的建议是让 WPF 和 Windows 窗体应用程序使用 Windows 社区工具包中提供的 XAML 岛 .NET 控件。 这些控件提供一个对象模型,用于模拟相应 WinRT XAML 控件的属性、方法和事件(或提供对它们的访问权限)。 它们还处理键盘导航和布局更改等行为。

有两组用于 WPF 和 Windows 窗体应用程序的 XAML 岛控件:包装控件和主机控件。

包装控件

WPF 和 Windows 窗体应用程序可以使用选定的 XAML 岛控件来包装特定 WinRT XAML 控件的界面和功能。 可以在 WPF 或 Windows 窗体项目的设计图面中直接添加这些控件,然后在设计器中像使用任何其他 WPF 或 Windows 窗体控件那样使用它们。

下述 WinRT XAML 包装控件目前在 Windows 社区工具包中提供。

控件 支持的 OS 的最低版本 说明
InkCanvas
InkToolbar
Windows 10 版本 1903 为 Windows 窗体或 WPF 桌面应用程序中基于 Windows Ink 的用户交互提供图面和相关的工具栏。
MediaPlayerElement Windows 10 版本 1903 嵌入一个用于在 Windows 窗体或 WPF 桌面应用程序中流式传输和呈现媒体内容(如视频)的视图。
MapControl Windows 10 版本 1903 使你能够在 Windows 窗体或 WPF 桌面应用程序中显示符号地图或相片级地图。

若要详细演练如何使用 WinRT XAML 包装控件,请参阅使用 XAML 岛在 C# WPF 应用中托管 UWP XAML 控件

主机控件

如果自定义控件和其他方案超出可用包装控件的涵盖范围,WPF 和 Windows 窗体应用程序也可使用 Windows 社区工具包中提供的 WindowsXamlHost 控件。

控件 支持的 OS 的最低版本 说明
WindowsXamlHost Windows 10 版本 1903 可以托管派生自 Windows.UI.Xaml.UIElement 的任何 WinRT XAML 控件,包括 Windows SDK 提供的任何第一方 WinRT XAML 控件以及自定义控件。

若要详细演练如何使用 WindowsXamlHost 控件,请参阅使用 XAML 岛在 C# WPF 应用中托管 UWP XAML 控件使用 XAML 岛在 WPF 应用中托管自定义 WinRT XAML 控件

将项目配置为使用 XAML 岛 .NET 控件

XAML 岛 .NET 控件需要 Windows 10 版本 1903 或更高版本。 若要使用这些控件,请安装下面列出的 NuGet 包之一。 这些包提供了使用 XAML 岛包装控件和主机控件所需的一切,并包括其他也是必需的相关 NuGet 包。

控件类型 NuGet 包 相关文章
包装控件 以下包的 6.0.0 版或更高版本: 使用 XAML 岛在 C# WPF 应用中托管 UWP XAML 控件
主机控件 以下包的 6.0.0 版或更高版本: 使用 XAML 岛在 C# WPF 应用中托管 UWP XAML 控件
在 WPF 应用中托管自定义 WinRT XAML 控件

请注意以下详细信息:

Web 视图控件

Windows 社区工具包还提供了以下 .NET 控件,用于在 WPF 和 Windows 窗体应用程序中托管 Web 内容的。 这些控件通常以 XAML 岛控件形式用于类似的桌面应用现代化方案,并保留在 XAML 岛控件所在的 Microsoft.Toolkit.Win32 存储库中。

控件 支持的 OS 的最低版本 说明
WebView Windows 10 版本 1803 使用 Microsoft Edge 呈现引擎来显示 Web 内容。
WebViewCompatible Windows 7 提供与更多 OS 版本兼容的 WebView 版本。 此控件使用 Microsoft Edge 呈现引擎在 Windows 10 版本 1803 及更高版本上显示 Web 内容,使用 Internet Explorer 呈现引擎在早期版本的 Windows 10、Windows 8.x 和 Windows 7 上显示 Web 内容。

若要使用这些控件,请安装以下 NuGet 包之一:

C++ 桌面 (Win32) 应用程序

C++ 桌面应用程序不支持 XAML Island .NET 控件。 这些应用程序必须改用 Windows 10 SDK(版本 1903 及更高版本)提供的 WinRT XAML 托管 API。

WinRT XAML 托管 API 包含多个 Windows 运行时类和 COM 接口,可供 C++ 桌面应用程序用来托管派生自 Windows.UI.Xaml.UIElement 的任何 WinRT XAML 控件。 可以在具有关联窗口句柄 (HWND) 的应用程序的任何 UI 元素中托管 WinRT XAML 控件。 有关此 API 的详细信息,请参阅以下文章。

注意

Windows 社区工具包中的包装控件和主机控件在内部使用 WinRT XAML 托管 API,并实现你在直接使用 WinRT XAML 托管 API 时需要自行处理的所有行为,包括键盘导航和布局更改。 对于 WPF 和 Windows 窗体应用程序,强烈建议使用这些控件而不是直接使用 WinRT XAML 托管 API,因为它们抽象掉了使用 API 的许多实现细节。

XAML 岛的体系结构

下图在体系结构上展现了如何在 WinRT XAML 托管 API 的基础上组织不同类型的 XAML 岛控件。

Host control Architecture

此图表底部所示的 API 随 Windows SDK 提供。 包装控件和主机控件可通过 Windows 社区工具包中的 NuGet 包获得。

限制和解决方法

以下各节讨论使用 XAML 岛的桌面应用中某些 UWP 开发方案的限制和解决方法。

仅通过使用变通方法支持

✔️ XAML 岛的当前版本有条件地支持在 XAML 岛中托管来自 WinUI 2 库的控件。 如果桌面应用将 MSIX 包用于部署,则可以承载来自 Microsoft.UI.Xaml NugGet 包的预发行版或发行版的 WinUI 控件。 如果桌面应用不是使用 MSIX 打包的,则只有在安装了 Microsoft.UI.Xaml NuGet 包的预发行版或使用动态依赖项 API 的情况下,才能承载 WinUI 控件。 以后的版本会支持托管来自 WinUI 3.0 库的控件。

✔️ 若要访问 XAML 岛中 XAML 内容树的根元素并获取在其中托管它的上下文的相关信息,请勿使用 CoreWindowApplicationViewWindow 类。 相反,请使用 XamlRoot 类。 有关详情,请参阅本部分

✔️ 若要支持来自 WPF、Windows 窗体或 C++ 桌面 (Win32) 应用的共享协定,应用必须使用 IDataTransferManagerInterop 接口获取 DataTransferManager 对象,以便为特定窗口启动共享操作。 有关演示如何在 WPF 应用中使用此接口的示例,请参阅 ShareSource 示例

✔️ 不支持在 XAML 岛中使用具有托管控件的 x:Bind。 必须在 .NET 标准库中声明数据模型。

不支持

🚫 在面向 .NET Framework 的 WPF 和 Windows 窗体应用中使用 XAML 岛。 仅面向 .NET Core 3.x 的应用支持 XAML 岛。

🚫 XAML 岛中的 UWP XAML 内容在运行时不响应 Windows 主题从深到浅的变化,反之亦然。 内容会响应运行时的高对比度更改。

🚫 添加 Windows.UI.Xaml.WebView 控件。 对于 WPF 和 WinForms 应用,请参阅这些替代方案

🚫 在全屏模式下不支持 MediaPlayer 控件和 MediaPlayerElement 主机控件。

🚫 带手写视图的文本输入。 有关此功能的详细信息,请参阅本文

🚫 使用 @Places@People 内容链接的文本控件。 有关此功能的详细信息,请参阅本文

🚫 XAML Islands 不支持托管一个包含接受文本输入的控件(例如 TextBoxRichEditBoxAutoSuggestBox)的 ContentDialog。 如果你托管了这样的 ContentDialog,输入控件将无法正确响应按键操作。 若要使用 XAML Islands 实现类似的功能,建议托管一个包含输入控件的 Popup

🚫 XAML 岛目前不支持在承载的 Windows.UI.Xaml.Controls.Image 控件中或通过使用 Windows.UI.Xaml.Media.Imaging.SvgImageSourc 对象显示 SVG 文件。 作为一种解决方法,请将要显示的图像文件转换为基于光栅的格式,如 JPG 或 PNG。

XAML 岛的窗口宿主上下文

在桌面应用中托管 XAML 岛时,可以同时在同一线程上运行多个 XAML 内容树。 若要访问 XAML 岛中 XAML 内容树的根元素并获取在其中托管它的上下文的相关信息,请使用 XamlRoot 类。 CoreWindowApplicationViewWindow 类不会为 XAML 岛提供正确的信息。 CoreWindowWindow 对象在线程上存在并且可供应用访问,但它们不会返回有意义的边界或可见性(它们始终不可见且大小为 1x1)。 有关详细信息,请参阅窗口化宿主

例如,若要获取包含 XAML 岛中所托管 WinRT XAML 控件的窗口的边界矩形,请使用控件的 XamlRoot.Size 属性。 由于可以在 XAML 岛中托管的每个 WinRT XAML 控件都派生自 Windows.UI.Xaml.UIElement,因此可以使用控件的 XamlRoot 属性来访问 XamlRoot 对象。

Size windowSize = myUWPControl.XamlRoot.Size;

不要使用 CoreWindows.Bounds 属性来获取边界矩形。

// This will return incorrect information for a WinRT XAML control that is hosted in a XAML Island.
Rect windowSize = CoreWindow.GetForCurrentThread().Bounds;

如果需要一个表,其中包含与窗口化相关的常见 API(应避免在 XAML 岛的上下文中使用)以及建议的 XamlRoot 替换项,请查看此部分中的表。

有关演示如何在 WPF 应用中使用此接口的示例,请参阅 ShareSource 示例

其他资源

有关如何使用 XAML 岛的更多背景信息和教程,请参阅以下文章和资源:

  • WPF 应用现代化教程:本教程提供的分步说明介绍了如何使用 Windows 社区工具包中的包装控件和主机控件向现有的 WPF 业务线应用程序添加 WinRT XAML 控件。 本教程包含 WPF 应用程序的完整代码,以及该过程中每个步骤的详细说明。
  • XAML Island 代码示例:此存储库包含的 Windows 窗体、WPF 和 C++ 桌面 (Win32) 应用示例演示了如何使用 XAML Island。
  • XAML Islands v1 - Updates and Roadmap(XAML 岛 v1 - 更新和路线图):此博客文章讨论了有关 XAML 岛的许多常见问题,并提供了详细的开发路线图。