演练 - 使用 WinUI 3 控件创建 C# 组件,并从使用 Windows 应用 SDK 的 C++/WinRT 应用中使用它
C#/WinRT 支持创作 Windows 运行时组件,包括 WinUI 自定义类型和自定义控件。 可以从使用 Windows 应用 SDK 的 C# 或 C++/WinRT 应用程序中使用这些组件。 建议使用 C#/WinRT v1.6.4 或更高版本创作具有 NuGet 打包支持的运行时组件。
有关支持的方案的更多详细信息,请参阅 C#/WinRT GitHub 存储库中的创作 C#/WinRT 组件。
本演练演示如何使用自定义 WinUI 3 控件创作 C# 组件,以及如何从使用 Windows 应用 SDK 项目模板的 C++/WinRT 应用中使用该组件。
必备条件
本演练需要下列工具和组件:
使用 Windows 应用 SDK 创作 C#/WinRT 组件
使用由 Windows 应用 SDK 提供的类库 (桌面版 WinUI 3)创建新的 C# 库项目。 在本演练中,我们将库项目命名为 WinUIComponentCs,将解决方案命名为 AuthoringWinUI。
取消选中“将解决方案和项目放在同一目录中”框(否则,上一节中 C++ 应用程序的
packages
文件夹最终会干扰 C# 库项目)。删除默认包含的
Class1.cs
文件。将最新的 Microsoft.Windows.CsWinRT NuGet 包安装到项目中。
i. 在“解决方案资源管理器”中,右键单击项目节点并选择“管理 NuGet 包”。
ii. 搜索“Microsoft.Windows.CsWinRT”NuGet 包,并安装最新版本。
将以下属性添加到库项目:
<PropertyGroup> <CsWinRTComponent>true</CsWinRTComponent> </PropertyGroup>
CsWinRTComponent
属性指定项目是 Windows 运行时组件,因此生成项目时会生成.winmd
文件。
将自定义控件或用户控件添加到库。 为此,请在 Visual Studio 中右键单击项目,单击“添加”>“新项”,然后在左窗格中选择“WinUI”。 在本演练中,我们添加了新的用户控件 (WinUI 3) 并将其命名为了
NameReporter.xaml
。 NameReporter 用户控件允许用户在相应的 TextBox 控件中输入名字和姓氏,然后单击按钮。 然后,该控件将显示一个消息框,其中包含用户输入的名字。将以下代码粘贴到
NameReporter.xaml
文件:<UserControl x:Class="WinUIComponentCs.NameReporter" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:WinUIComponentCs" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <StackPanel HorizontalAlignment="Center"> <StackPanel.Resources> <Style x:Key="BasicTextStyle" TargetType="TextBlock" BasedOn="{StaticResource BodyTextBlockStyle}"> <Setter Property="Margin" Value="10,10,10,10"/> </Style> </StackPanel.Resources> <TextBlock Text="Enter your name." Margin="0,0,0,10"/> <StackPanel Orientation="Horizontal" Margin="0,0,0,10"> <TextBlock Style="{StaticResource BasicTextStyle}"> First Name: </TextBlock> <TextBox Name="firstName" /> </StackPanel> <StackPanel Orientation="Horizontal" Margin="0,0,0,10"> <TextBlock Style="{StaticResource BasicTextStyle}"> Last Name: </TextBlock> <TextBox Name="lastName" /> </StackPanel> <Button Content="Submit" Click="Button_Click" Margin="0,0,0,10"/> <TextBlock Name="result" Style="{StaticResource BasicTextStyle}" Margin="0,0,0,10"/> </StackPanel> </UserControl>
将以下方法添加到
NameReporter.xaml.cs
:using System.Text; ... private void Button_Click(object sender, RoutedEventArgs e) { StringBuilder displayText = new StringBuilder("Hello, "); displayText.AppendFormat("{0} {1}.", firstName.Text, lastName.Text); result.Text = displayText.ToString(); }
接下来即可生成 WinUIComponentCs 项目以为组件生成
.winmd
文件。
注意
还可将组件打包为供最终用户引用的 NuGet 包。 有关详细信息,请参阅 C#/WinRT Github 存储库上的创作 C#/WinRT 组件。
从 Windows 应用 SDK C++/WinRT 应用引用组件
以下步骤演示如何从 C++/WinRT Windows 应用 SDK 应用程序使用上一部分创建的组件。 使用 C++ 中的 C#/WinRT 组件当前需要使用单项目打包的空白应用(桌面版 WinUI 3)模板。 请注意,还可从没有类注册的 C# 打包应用引用 C# 组件。
目前不支持使用单独的 Windows 应用程序打包 (WAP) 项目的打包应用。 有关受支持的项目配置的最新更新,请参阅 C#/WinRT GitHub 存储库中的创作 C#/WinRT 组件。
将新的 C++ Windows 应用 SDK 应用程序项目添加到解决方案中。 在 Visual Studio 中右键单击解决方案,然后选择“添加”>“新项目”。 选择由 Windows 应用 SDK 提供的 C++ 打包的空白应用(桌面版 WinUI 3)模板。 在本演练中,我们将该应用命名为 CppApp。
将 C++ 应用的项目引用添加到 C# 组件。 在 Visual Studio 中,右键单击 C++ 项目,并选择“添加”>“引用”,然后选择 WinUIComponentCs 项目。
注意
支持将组件用作 NuGet 包引用,但存在一些限制。 也就是说,具有自定义用户控件的组件当前不能用作 NuGet 包引用。
在应用的
pch.h
头文件中,添加以下行:#include <winrt/WinUIComponentCs.h> #include <winrt/WinUIComponentCs.WinUIComponentCs_XamlTypeInfo.h>
打开程序包清单文件
Package.appxmanifest
。注意
存在一个已知问题,即
Package.appxmanifest
文件不会显示在Visual Studio 解决方案资源管理器中。 要解决此问题,请右键单击 C++ 项目,选择“卸载项目”,然后双击项目以打开CppApp.vcxproj
文件。 将以下条目添加到项目文件,然后重新加载项目:<ItemGroup> <AppxManifest Include="Package.appxmanifest"> <SubType>Designer</SubType> </AppxManifest> </ItemGroup>
在
Package.appxmanifest
中,添加以下可激活类注册。 还需要为 WinUIComponentCs.WinUIComponentCs_XamlTypeInfo.XamlMetaDataProvider 类添加一个额外的ActivatableClass
条目,才能激活 WinUI 类型。 右键单击Package.appxmanifest
文件并选择“打开方式”>“XML (文本编辑器)”以编辑文件。<!--In order to host the C# component from C++, you must add the following Extension group and list the activatable classes--> <Extensions> <Extension Category="windows.activatableClass.inProcessServer"> <InProcessServer> <Path>WinRT.Host.dll</Path> <ActivatableClass ActivatableClassId="WinUIComponentCs.NameReporter" ThreadingModel="both" /> <ActivatableClass ActivatableClassId="WinUIComponentCs.WinUIComponentCs_XamlTypeInfo.XamlMetaDataProvider" ThreadingModel="both" /> </InProcessServer> </Extension> </Extensions>
打开
MainWindow.xaml
文件。i. 添加对文件顶部组件命名空间的引用。
xmlns:custom="using:WinUIComponentCs"
ii. 将用户控件添加到现有 XAML 代码。
<StackPanel> ... <custom:NameReporter/> </StackPanel>
将 CppApp 设置为启动项目 - 右键单击 CppApp,然后选择“设为启动项目”。 将解决方案配置设置为
x86
。 在生成之前,可能还需要重新定位解决方案目标,以使用 Visual Studio 2022 生成工具进行生成。 右键单击解决方案,选择“重定目标解决方案”,并将平台工具集升级到 v143。生成并运行应用以查看自定义 NameReporter 控件。
已知问题
- 使用 C# 组件作为项目引用需要将
PublishReadyToRun
设置为False
。 有关更多详细信息,请参阅 Github 问题 #1151。 - 当前仅
x86
应用程序支持从 C++ 使用为AnyCPU
构建的 C# 组件。x64
和Arm64
应用会导致类似于以下内容的运行时错误:%1 不是有效的 Win32 应用程序。有关详细信息,请参阅 Github 问题 #1151。