本主题指导你使用 C++/WinRT 创建 Windows 通用 Windows 平台 (UWP) “Hello, World!” 应用。 应用的用户界面(UI)是使用可扩展应用程序标记语言(XAML)定义的。
C++/WinRT 是 Windows 运行时 (WinRT) API 的完全标准的现代C++17 语言投影。 有关详细信息以及更多演练和代码示例,请参阅 C++/WinRT 文档。 一个很好的主题是 开始使用 C++/WinRT。
为 C++/WinRT 设置 Visual Studio
有关设置 Visual Studio 进行 C++/WinRT 开发的信息(包括安装和使用 C++/WinRT Visual Studio 扩展(VSIX)和 NuGet 包(它们同时提供项目模板和生成支持),请参阅 Visual Studio 对 C++/WinRT的支持。
若要下载 Visual Studio,请参阅 下载。
有关 XAML 简介,请参阅 XAML 概述
创建空白应用程序(HelloWorldCppWinRT)
我们的第一个应用是“Hello, World!” 应用,它演示了交互、布局和样式的一些基本功能。
首先,在 Microsoft Visual Studio 中创建新项目。 创建一个 空白应用(C++/WinRT) 项目,并将其命名为 HelloWorldCppWinRT。 确保 在同一目录中放置解决方案和项目 未选中。 以 Windows SDK 的最新正式可用版本(即非预览版)为目标。
在本主题的后面部分中,你将被引导去构建这个项目(但在那之前不要构建)。
关于项目文件
通常,在项目文件夹中,每个 .xaml
(XAML 标记) 文件都有相应的.idl
文件和.h
.cpp
文件。 这些文件一起编译为 XAML 页面类型。
可以修改 XAML 标记文件以创建 UI 元素,并且可以将这些元素绑定到数据源(称为 数据绑定的任务)。 例如,您修改 .h
和 .cpp
文件(有时还包括 .idl
文件)以为您的 XAML 页添加自定义逻辑,比如事件处理程序。
让我们看看一些项目文件。
-
App.idl
、App.xaml
、App.h
和App.cpp
。 这些文件表示您的应用对 Windows::UI::Xaml::Application 类的专门化,其中包括应用的入口点。App.xaml
不包含任何特定于页面的标记,但你可以在此处添加用户界面元素样式,以及要从所有页面访问的任何其他元素。.h
和.cpp
文件包含用于各种应用程序生命周期事件的处理程序。 通常,可以在其中添加自定义代码,以在应用启动时初始化应用,并在应用暂停或终止时执行清理。 -
MainPage.idl
、MainPage.xaml
、MainPage.h
和MainPage.cpp
。 在应用中包含默认主(启动)页面类型的 XAML 标记和实现,即 MainPage 运行时类。 MainPage 没有导航支持,但它提供了一些默认 UI 和事件处理程序来帮助你入门。 -
pch.h
和pch.cpp
。 这些文件表示项目的预编译头文件。 在pch.h
中,包括不经常更改的任何头文件,然后在项目中的其他文件中包含pch.h
。
第一次查看代码
运行时类
如你所知,使用 C# 编写的通用 Windows 平台(UWP)应用中的所有类都是 Windows 运行时类型。 但是,在 C++/WinRT 应用程序中创作类型时,可以选择该类型是 Windows 运行时类型还是常规C++类/结构/枚举。
项目中的任何 XAML 页面类型都需要是 Windows 运行时类型。 因此 MainPage 是 Windows 运行时类型。 具体而言,它是一个 运行时类。 XAML 页面所使用的任何类型也需要是 Windows 运行时类型。 编写 Windows 运行时组件时,若想创建可供其他应用使用的类型,那么你需要创建一个 Windows 运行时类型。 在其他情况下,类型可以是常规C++类型。 通常,可以使用任何 Windows 运行时语言来使用 Windows 运行时类型。
一个好的指示是类型是 Windows 运行时类型,它是在接口定义语言()文件中 .idl
中定义的。 让我们以 MainPage 为例。
// MainPage.idl
namespace HelloWorldCppWinRT
{
[default_interface]
runtimeclass MainPage : Windows.UI.Xaml.Controls.Page
{
MainPage();
Int32 MyProperty;
}
}
这是 MainPage 运行时类及其激活工厂的基本实现结构,如 MainPage.h
所示。
// MainPage.h
...
namespace winrt::HelloWorldCppWinRT::implementation
{
struct MainPage : MainPageT<MainPage>
{
MainPage();
int32_t MyProperty();
void MyProperty(int32_t value);
...
};
}
namespace winrt::HelloWorldCppWinRT::factory_implementation
{
struct MainPage : MainPageT<MainPage, implementation::MainPage>
{
};
}
有关是否应为给定类型创作运行时类的更多详细信息,请参阅主题 使用 C++/WinRT创作 API。 有关运行时类与 IDL(.idl
文件)之间的连接的详细信息,您可以阅读并学习主题 XAML 控件——绑定到 C++/WinRT 属性。 本主题介绍创作新运行时类的过程,第一步是向项目添加新 Midl File (.idl) 项。
现在,让我们向 HelloWorldCppWinRT 项目添加一些功能。
步骤 1. 修改启动页
在 解决方案资源管理器中,打开 MainPage.xaml
,以便可以创作构成用户界面(UI)的控件。
删除其中已有的 StackPanel 及其所有内容。 在该位置,粘贴以下 XAML。
<StackPanel x:Name="contentPanel" Margin="120,30,0,0">
<TextBlock HorizontalAlignment="Left" Text="Hello, World!" FontSize="36"/>
<TextBlock Text="What's your name?"/>
<StackPanel x:Name="inputPanel" Orientation="Horizontal" Margin="0,20,0,20">
<TextBox x:Name="nameInput" Width="300" HorizontalAlignment="Left"/>
<Button x:Name="inputButton" Content="Say "Hello""/>
</StackPanel>
<TextBlock x:Name="greetingOutput"/>
</StackPanel>
此新的 StackPanel 包含一个用于提示输入用户名的 TextBlock,一个用于接受用户名的 TextBox,一个 Button,以及另一个 TextBlock 元素。
由于我们删除了名为 Button 的 myButton,因此我们必须从代码中删除对它的引用。 因此,在 MainPage.cpp
MainPage::ClickHandler 函数中删除代码行。
此时,你已创建了一个非常基本的通用 Windows 应用。 若要查看 UWP 应用的外观,请生成并运行应用。
在应用中,可以键入到文本框中。 但单击该按钮尚未产生任何效果。
步骤 2. 添加事件处理程序
在 MainPage.xaml
中,找到名为 inputButton的 Button,并为其 ButtonBase::Click 事件注册事件处理程序。
按钮的标记现在应如下所示。
<Button x:Name="inputButton" Content="Say "Hello"" Click="inputButton_Click"/>
实现如下所示的事件处理程序。
// MainPage.h
struct MainPage : MainPageT<MainPage>
{
...
void inputButton_Click(
winrt::Windows::Foundation::IInspectable const& sender,
winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
};
// MainPage.cpp
namespace winrt::HelloWorldCppWinRT::implementation
{
...
void MainPage::inputButton_Click(
winrt::Windows::Foundation::IInspectable const& sender,
winrt::Windows::UI::Xaml::RoutedEventArgs const& e)
{
greetingOutput().Text(L"Hello, " + nameInput().Text() + L"!");
}
}
有关详细信息,请参阅使用委托处理事件。
实现从文本框中检索用户的名称,使用它创建问候语,并在 greetingOutput 文本块中显示该名称。
生成并运行应用。 在文本框中键入名称,然后单击该按钮。 应用显示个性化问候语。
步骤 3. 设置启动页面的样式
“选择主题”
可以轻松自定义应用的外观。 默认情况下,你的应用使用具有浅色样式的资源。 系统资源还包括深色主题。
若要试用深色主题,请编辑 App.xaml
并添加 Application::RequestedTheme 的值。
<Application
...
RequestedTheme="Dark">
</Application>
对于主要显示图像或视频的应用,我们建议使用深色主题;对于包含大量文本的应用,我们建议使用浅色主题。 如果你使用的是自定义配色方案,则使用最适合你的应用外观的主题。
注释
应用启动时应用主题。 应用运行时无法更改它。
使用系统样式
在本部分中,我们将更改文本的外观(例如,使字号变大)。
在 MainPage.xaml
中,找到 文本块中的“你叫什么名字?”。 将其 Style 属性设置为对 BaseTextBlockStyle 系统资源键的引用。
<TextBlock Text="What's your name?" Style="{ThemeResource BaseTextBlockStyle}"/>
BaseTextBlockStyle 是 中 \Program Files (x86)\Windows Kits\10\DesignTime\CommonConfiguration\Neutral\UAP\<version>\Generic\generic.xaml
中定义的资源的关键。 下面是由该样式设置的属性值。
<Style x:Key="BaseTextBlockStyle" TargetType="TextBlock">
<Setter Property="FontFamily" Value="XamlAutoFontFamily" />
<Setter Property="FontWeight" Value="SemiBold" />
<Setter Property="FontSize" Value="14" />
<Setter Property="TextTrimming" Value="None" />
<Setter Property="TextWrapping" Value="Wrap" />
<Setter Property="LineStackingStrategy" Value="MaxHeight" />
<Setter Property="TextLineBounds" Value="Full" />
</Style>
此外,在 MainPage.xaml
中,找到名为 的 greetingOutput
。 将其 样式 也设置为 BaseTextBlockStyle。 如果立即生成并运行应用,你将看到这两个文本块的外观已更改(例如,字号现在更大)。
步骤 4. 让 UI 适应不同的窗口大小
现在,我们将使 UI 动态适应不断变化的窗口大小,使其在具有小显示器的设备上看起来不错。 为此,请将 VisualStateManager 部分添加到 MainPage.xaml
。 你将为不同的窗口大小定义不同的视觉状态,然后设置要应用于其中每个视觉状态的属性。
调整 UI 布局
将此 XAML 块添加为根 StackPanel 元素的第一个子元素。
<StackPanel ...>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState x:Name="wideState">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="641" />
</VisualState.StateTriggers>
</VisualState>
<VisualState x:Name="narrowState">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="0" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="contentPanel.Margin" Value="20,30,0,0"/>
<Setter Target="inputPanel.Orientation" Value="Vertical"/>
<Setter Target="inputButton.Margin" Value="0,4,0,0"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
...
</StackPanel>
生成并运行应用。 请注意,UI 看起来和之前一样,直到窗口缩小到窄于 641 设备无关像素(DIP)。 此时,将应用 narrowState 视觉状态,并连同该状态一起应用所有为该状态定义的属性设置器。
名为wideState
的VisualState中包含一个AdaptiveTrigger,其MinWindowWidth属性设置为641。 这意味着仅当窗口宽度不小于 641 个 DIP 的最小值时,才会应用状态。 您没有为此状态定义任何 Setter 对象,因此它使用在 XAML 中为页面内容定义的布局属性。
第二个 VisualState, narrowState
具备一个 AdaptiveTrigger,其 MinWindowWidth 属性设置为 0。 当窗口宽度大于 0 但小于 641 DIP 时,将应用此状态。 在恰好 641 个 DIP 时,wideState
生效。 在中 narrowState
,定义 Setter 对象以更改 UI 中控件的布局属性。
- 将 contentPanel 元素的左边距从 120 减少到 20。
- 将 inputPanel 元素的 方向 从 水平 更改为 垂直。
- 向 输入按钮 元素添加 4DIP 的上边距。
概要
本演练演示了如何将内容添加到 Windows 通用应用、如何添加交互以及如何更改 UI 的外观。