10. 应用开发:C++/C# 和 WinUI3
🤖 作者:包瑞清(richie bao): lastmod: 2025-01-07T09:39:35+08:00
10.1 框架选择, VS 安装项
10.1.1 框架选择
Windows 提供了广泛的编程语言、框架(frameworks)和工具来构建应用程序,包括WinUI、UWP(Universal Windows Platform)、桌面版 React Native、WPF(Windows Presentation Foundation)、Windows Forms,以及多种跨平台跨平台框架。支持的编程语言包括 C++、C#,JavaScript等。针对 Windows 开发应用程序的多种选择,其最佳选项取决于用户对应用程序的需求、编程语言的选择和对相关技术的熟悉程度。表列出了当前 Windows 最流行的应用开发框架(App Development Frameworks)及其支持的功能。
表:应用开发框架功能比较(表引自,Overview of framework options)
Feature(功能)\框架 | .NET MAUI | Blazor Hybrid | React Native for Desktop | UWP XAML (Windows.UI.Xaml) | Win32 (MFC or ATL) | Windows Forms | WinUI 3 | WPF |
---|---|---|---|---|---|---|---|---|
Language(支持的语言) | C# | C# | JavaScript, TypeScript | C#, C++, Visual Basic | C++, Rust | C#, Visual Basic | C#, C++ | C#, Visual Basic |
UI language(用户界面语言) | XAML/Code | Razor | JSX | XAML | Code | Code | XAML | XAML |
UI designer(用户界面设计器) | ❌ | ❌ | ❌ | ✅ | ❌ | ✅ | ❌ | ✅ |
UI debugging(用户界面调试) | Hot Reload | Hot Reload | Fast Refresh | Hot Reload | - | Hot Reload | Hot Reload | Hot Reload |
Fluent Design | ✅ | ✅ | ✅ | ✅ (via WinUI 2) | ❌ | ❌ | ✅ | ❌ |
.NET | .NET | .NET | N/A | .NET Core & .NET Native | N/A | .NET & .NET Framework | .NET | .NET & .NET Framework |
Windows App SDK(Software Development Kit) | ✅ (more info) | ✅ via MAUI | ✅ (more info) | ❌ | ✅ | ✅ (more info) | ✅ | ✅ (more info) |
Great for touch(适合触摸操作) | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ | ❌ |
Cross-platform(跨平台) | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
Xbox/HoloLens apps | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ |
Sandboxing (AppContainer) | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ |
Currently supported(当前支持) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
Receiving updates(接收更新) | ✅ | ✅ | ✅ | ✅ (security & bugfix) | ✅ | ✅ | ✅ | ✅ |
Roadmap(开发路径) | GitHub | GitHub | GitHub | n/a | n/a | GitHub | GitHub | GitHub |
XAML(Extensible Application Markup Language),是微软开发的标记语言,主要用于构建用户界面(UI),允许开发者通过简单的 XML 结构定义控件、布局、样式和事件,类似于 HTML 和 XML,可以清晰的分离界面的结构(标记部分)与逻辑(代码部分)。 XAML 是一种声明式语言(Declarative Language),可以使用一种语言结构初始化对象并设置对象的属性,这种结构展示了多个对象之间的层级关系,并通过支持扩展类型的类型约定来扩展类型,这意味着开发者通过 XAML 语言定义界面元素的外观和布局,而不是通过编程方式逐步构建界面。声明式的方式使得界面的结构清晰易懂,且易于维护。XAML 语言支持在开发过程中不同工具和角色之间交换源代码,例如在设计工具和互动开发环境(Interactive Development Environment,IDE)之间交换 XAML 源代码,或在开发人员之间交换源代码。通过 XAML 作为交换格式,可以保持设计师角色和开发者角色的独立性或将其结合起来,并在开发过程中不断迭代代码。XAML 语言文件扩展名通常为 .xaml
,可以通过可视化设计工具(用户界面设计,UI designer)进行编辑和预览,并支持数据绑定,允许控件的属性与后台数据模型直接连接,使得 UI 更新与数据源保持同步,便于实现响应式界面,是现代 Windows 应用程序开发不可或缺的组成部分。
Fluent Design (System) ,是微软提出的一种设计语言,旨在提供更加现代化、灵活且互动性强的体验,其首次在 Windows 10 中提出,并随着 Windows11 及其他微软产品的开发不断演进。Fluent Design 强调视觉、声音、动画和触感的统一,旨在为开发者提供更直观和丰富的互动界面,其设计理解基于的主要核心要素有光纤(Light)、深度(Depth)、运动(Motion)、材质(Material)和缩放(Scale)等。Fluent2 是 Fluent Design(Fluent1)的迭代版本,提供了更多的视觉效果和更强大的互动支持,着重提升了现代操作系统和应用的用户体验,更具沉浸感和动态感的交换界面。WinUI3 是 Windows App SDK 的一部分,包含了 Fluent2 的最新设计控件和效果。开发者可以通过 WinUI 控件轻松实现 Fluent2 风格的 UI,为开发现代桌面和跨平台应用的一个重要设计语言,已帮助开发者创建更美观、直观且一致的用户界面。
Windows App SDK,是微软提供的一组新的开发者组件和工具,代表了 Windows 应用开发平台的下一次演进,其提供了一套任何 Window11 上的桌面应用都可以一致使用的统一的应用程序接口(Application Programming Interface ,APIs) 和组件,并且向下兼容 Windows10,版本1809及以上。Windows APP SDK 并不替代 Windows SDK 或现有的桌面 Windows 应用类型,例如 .NET(包括 Windows Forms 和 WPF)及使用 C++ 的桌面 Win32 应用。相反,Windows App SDK补充了这些现有工具和应用类型,提供了一套开发者可以在这些平台上依赖的公共 API,包括 WinUI3。
通过参考应用开发框架功能比较表,选择的框架应该能够同时支持 C++ 和 C#,以便比较演示两种语言的应用开发;并支持 XAML 标记语言,方便构建 UI;最好支持 Fluent Design,用于建立现代感十足的界面设计; 且为微软当前和未来持续维护更新,主流的框架。因此选择 WinUI3 框架构建应用开发程序。
WinUI3 是微软推出的一个现代化 UI 框架,专为 Windows 应用开发而设计,是 Windows App SDK 的一部分。WinUI3 是在 UWP(Universial Windows Platform)和 WPF(Windows Presentation Foundation)的基础上发展而来,旨在提供更加一致和灵活的跨平台开发体验,支持 Windows10 和 Windows11 应用的开发。WinUI3 的核心特性和优势包括:
- 现代化的 UI 控件和样式。WinUI3 包含了 Fluent2 的最新设计控件和效果,可以帮助开发者创建更美观、现代、和响应式的应用界面;并支持更高效的自定义样式。
- 跨平台支持。WinUI3 支持在 Windows10 和Windows11 上运行,且在未来支持更多的 Windows 设备(如 PC、平板和可穿戴设备)和平台。
- 支持桌面应用。WinUI3 允许开发者创建传统的桌面应用程序,而不仅仅是 UWP 应用,并兼容现有的 Windows 桌面技术,如 WPF 和WinForms(Wndows Forms)。对于传统桌面开发,WinUI3 提供了同一的 UI 和控件,以便开发者更加方便的开发现代化的桌面应用。
- 高性能和可扩展性。WinUI3 提供了高性能的 UI 渲染,可以在不同的设备上运行时提供流畅的动画、图形和交互;并支持 MVVM (Model-View-ViewModel)架构,帮助分离数据层、界面层和逻辑层,有助于提高应用的可维护性和扩展性。
- 与 .NET 和 C++ 兼容。 WinUI3 支持 C# 和 XAML 开发,可以通过 .NET 和 C# 编写应用程序的逻辑;并支持 C++/WinRT,使得开发者可以使用 C++ 语言来构建 Windows 应用程序。
- 支持多平台和开发工具。通过 Windows App SDK,WinUI3 可以与其他现代 Windows 开发工具和库集成;并支持 Visual Studio、Visual Studio Code 等开发环境。
10.1.2 技术/组件关系梳理
前文中涉及到框架 WinUI,标记语言 XAML, C++/WinRT,Windows App SDK 和 Fluent Design System 等技术,其之间的关系如表,
技术/组件 | 作用/功能 | 关系 | 说明 |
---|---|---|---|
WinUI3 | 现代化 UI 框架,用于构建 Windows 应用用户界面 | 与 XAML 配合使用,构建 UI;与 Fluent Design System 配合,提供现代化的设计风格 | 提供一套现代 UI 控件和设计规范,支持响应式和动态 UI 元素 |
XAML | 用于声明式界面设计的标记语言 | 与 WinUI3 配合, 定义界面元素和布局 | 声明界面结构、支持数据绑定和与后台(代码)逻辑的交互 |
C++/WinRT | C++ 与 WinRT API 的互操作库 | 使 C++ 开发者能够调用 WinRT API,支持 Windows 应用开发 | 作为后台代码(backing code),处理应用的业务逻辑,操作系统服务,及与 UI 的交互 |
WinRT | Windows Runtime API, 提供底层操作系统服务 | 被 C++/WinRT 或 C# 访问,提供文件管理,UI 控件等服务 | 提供应用开发所需的操作系统 API,可通过 C++/WinRT 调用 |
Window App SDK | 开发框架,整合多种工具和库 | 整合了 WinUI3、C++/WinRT、WinRT,为开发者提供跨版本的 Windows 应用开发工具 | 简化 Windows 应用开发,支持最新功能和跨版本的兼容性 |
Fluent Design System | 设计语言,提供现代的视觉风格 | 在 WinUI3 中实现,用于增强 UI 的外观和交互性 | 提供光影、透明度、动画等视觉效果,通过 WinUI3 实现控件的外观设计 |
WinUI3 是开发 Windows 应用界面的框架,结合了标记语言 XAML 和 Fluent Design System 实现现代化的用户界面设计;C++/WinRT 和 WinRT 提供底层 API 支持,供开发者用高性能代码实现应用逻辑;Windows App SDK 将所有开发工具(如 WinUI、WinRT 等)打包,成为现代 Windows 应用开发的基础。
10.1.3 VS 安装项
在安装 Visual Studio[2022](VS)时,需要安装用于开发 WinUI 和 Windows App SDK 所需的工作负载(workloads)和组件(components)。如果已完成安装,但没有勾选相关负载和组件时,则可以打开 Visual Studio Installer应用,选择修改以添加所需负载和组件。在 VS 安装程序的 workloads 选项卡中,使用 Windows App SDK,开发 C# 应用程序,需要选择负载Windows application development
。如果开发 C++ 应用程序,则还需要在Installation Details
(安装详情)面板中勾选C++ WinUI app development tools
,如图。
图 10-1 VS 安装勾选模块
Windows 为开发者提供了一种特殊模式,可以调整安全设置以运行正在开发的应用程序。在使用 VS 构建、部署和测试应用程序前需要启用Developer Mode
,其位于Windows 设置->System->For developers
页面下。
VS 项目模板包括快速创建应用程序所需的所有文件,在从 WinUI3 应用程序模板VS->Create a new project->Blank App, Packaged (WinUI 3 in Desktop)
(如图)创建项目后(项目名称起名为WinUI3Cpp
),就已经内置了一个可以运行的应用程序(如图),可以在Soluution Explorer
中查看文件结构,并打开文件查看代码。执行Start Debugging[Local Machine]
(快捷键 F5)后,结果如图,可以用Live Visual Tree
,XAML Live Preview
与.xaml
代码行交互定位来辅助设计 UI 界面,诊断可能出现的问题,调试代码。同时,编译该项目,部署到本地机器上,并在调试模式下运行,结果如图。
图 10-2 选择 Blank App, Packaged (WinUI 3 in Desktop)
图 10-3 打开应用程序,查看文件结构
图 10-4 运行后的界面,查看 Live Visual Tree,XAML Live Preview 及 Diagnostic Tools
图 10-5 应用程序运行结果,点击按钮前后变化
Windows App SDK(含 WinUI)作为 NuGet 包发布,意味着更新可能会与 Windows 和 VS 的更新不同步。因此,创建项目的 VS 模板可能没有引用最新的 Windows App SDK NutGet 包。为了确保获得最新的功能和修复,建议每次在 VS 中创建新项目时更新 NutGet 包,其位于 VS->Tools->NuGet Package Manager->Manage NuGet Packages for Solution...
下。
10.2 默认应用(C++)代码解读和 Hello world!
10.2.1 默认应用(C++)代码解读
Blank App, Packaged (WinUI 3 in Desktop)
模板创建了一个带有交互式按钮的窗口(图10-5),当点击按钮后,显示在按钮上的文字Click Me
会变为Clicked
。
10.2.1.1 项目文件结构
首先查看Solution Explorer
(解决方案的资源管理器),即项目的文件结构,如图10-3,各文件的具体解释如下表,
表,文件说明,参考调整于 Build a Hello World app using C# and WinUI 3 / Windows App SDK(https://learn.microsoft.com/en-us/windows/apps/how-tos/hello-world-winui3)
项(Item) | 描述(Description) |
---|---|
Solution 'WinUI3Cpp' |
为一个解决方案(一个解决方案可以包含多个项目(Project)),是项目的逻辑容器(Logical container)。项目通常是应用程序(Apps),但也支持类库(class libraries) 。此处的解决方案名称为WinUI3Cpp |
WinUI3Cpp(Desktop) |
为一个项目,是应用程序文件的逻辑容器,用于构建基于 WinUI3 的桌面应用程序。名称与创建项目时,同为该项目起的名称 |
External Dependencies 和 References |
为应用依赖的框架(如,.NET ,Windows SDK 等)和包(如,Windows App SDK );也包含开发者在应用中引入的其他功能和第三方库 |
Assets |
资产文件夹,包含用于应用程序的图标、图像和其它媒体资产,为保存用户界面需要的静态文件 |
App.manifest |
这个应用程序清单文件包含与应用安装在用户设备上时 Windows 显示应用程序方式相关的配置 |
App.xaml |
该标记文件指定应用所依赖的,共享并全局可访问的资源,相关联的代码文件有App.xaml.cpp 和App.xaml.h |
App.xaml.cpp 和 App.xaml.h |
.cpp 代码后置(code-behind)文件表示应用程序业务逻辑(business logic)的入口点,负责创建和激活MainWindow 实例。.h 为声明.cpp 的头文件,定义应用程序类App 的接口 |
MainWindow.xaml |
该标记文件包含了应用程序主窗口展示的相关内容 |
MainWindow.xaml.cpp 和 MainWindow.xaml.h |
.cpp 代码后置(code-behind)文件包含了与应用程序主窗口相关的业务逻辑。.h 声明与MainWindow.xaml 界面逻辑相关的类和成员函数 |
MainWindow.xaml.idl |
IDL(Interface Definition Language)文件用于定义应用程序与WinRT 接口的交互,提供了MainWindow 类的 WinRT 投影接口 |
module.g.cpp |
模块生成文件,通常由工具生成,负责与WinRT 或COM 模块的交互,包含项目模块的初始化和其他低级别设置 |
Package.appxmanifest |
这个包清单文件为开发者提供发布信息、图标、处理器架构和其他细节的配置信息,及应用程序在 Windows Store 中显示方式等内容,通常包括的版块有Application 、Visual Assets 、Capabilities 、Declarations 、Content URIs 和Packaging 等 |
packages.config |
为包管理配置文件,记录了项目所依赖的包,如Microsoft.WindowsAppSDK 、Microsoft.Windows.SDK.BuildTools 、Microsoft.Windows.ImplementationLibrary 、Microsoft.Windows.CppWinRT 和Microsoft.Web.WebView2 等 |
pch.cpp 和 pch.h |
预编译头文件,.h 包含项目中常用的头文件,以减少重复编译,提供编译速度;.cpp 编译.h 中的内容,生成预编译头文件 |
readme.txt |
说明文档,通常包含关于项目的基本信息,如项目的功能描述、编译和运行步骤及作者信息等 |
wil.natvis |
该文件是一个用于自定义如何在调试器的Locals 和Watch 窗口中显示来自 Windows 实现库(Windows Implementation Library,WIL)的本地 C++ 对象的文件,其允许在调试 C++ 应用程序时,更友好地查看复杂的数据结构。本质上,是通过Nativs 框架为 WIL 类型提供了自定义可视化,使开发者能够在 VS 调试器中更容易理解这些类型的内容 |
上述WinUI3 C++
桌面项目,其文件结构可以主要概况为:
- 项目基础文件(
app.manifest
,Package.appxmanifest
):配置应用元数据和权限。 - 用户界面文件/标记文件(
App.xaml
,MainWindow.xaml
):配置应用的外观和主窗口。 - 代码逻辑文件/代码文件(
*.cpp
,*.h
):实现和声明应用程序功能。 - 资源文件(
Assets
):存储应用所需的静态资源。 - 工具生成文件(
module.g.cpp
,wil.natvis
):辅助WinRT
和调试器工作。
10.2.1.2 主窗口实现
主窗口实现主要包括一个标记文件MainWindow.xaml
和一个代码文件MainWindow.xaml.cpp
,及其对应的头文件MainWindow.xaml.h
,及MainWindow.idl
IDL 文件。
文件 | MainWindow.xaml | MainWindow.xaml.h | MainWindow.xaml.cpp | MainWindow.idl |
---|---|---|---|---|
代码 |
|
|
|
|
🤖 代码解读 |
这段 XAML 标记代码定义了一个简单的 WinUI3 应用界面,包含一个水平排列、居中对齐的 |
这两个方法定义了一个属性的
位于头文件(.h)的这些方法目前没有实现,通常会在对应的实现文件(.cpp)中提供具体的实现。
这段代码是 |
为条件编译,检查
这段代码是 |
这个 IDL 文件定义了一个 |
10.2.2 Hello world!
基于既有默认应用,按钮点击后除了改变按钮的显示内容从Click Me
,修改为Clicked
外;增加TextBlock
控件显示文本,点击按钮前显示文本内容为Hi, there.
,点击按钮后显示文本内容为Hello World!
。另外,通过检索WinUI 3 Gallery(需从给出的链接下载安装程序,安装后运行查看)现代 UI 框架提供的示例应用,重新配置了按钮的样式,及配置文本显示的字体样式。并将应用的 UI 主题色由暗色模式Dark
调整为了亮色模式Light
,结果如图10-6。
图 10-6 Hello World! 点击按钮前后
首先在MainWindow.xaml
UI 界面标记文件中调整按钮Button
的样式;并增加文本块TextBlock
控件。调整StackPanel
中的样式为Orientation="Vertical"
以垂直向布局按钮和文本块。并修改了窗口的标题为HelloWorld!
,修改和增加部分的代码如下,
...
Title="HelloWorld!">
<StackPanel Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Center">
<Button x:Name="myButton" Click="myButton_Click" Content="Click Me" Style="{StaticResource AccentButtonStyle}" HorizontalAlignment="Center"/>
<TextBlock x:Name="TB_SayHi" FontFamily="Arial" FontSize="24" FontStyle="Italic" TextWrapping="WrapWholeWords" CharacterSpacing="200" Foreground="CornflowerBlue" Text="Hi, there." Margin="0,10,0,0" />
</StackPanel>
不需要修改MainWindow.xaml.h
头文件,只在MainWindow.xaml.cpp
代码文件下myButton_Click
按钮点击事件的处理函数中增加修改名为x:Name="TB_SayHi"
文本块TextBlock
的文本内容,修改的部分代码如下,
void MainWindow::myButton_Click(IInspectable const&, RoutedEventArgs const&)
{
myButton().Content(box_value(L"Clicked"));
TB_SayHi().Text(L"Hello World!");
}
TB_SayHi().Text(L"Hello World!");
中TB_SayHi()
是对MainWindow
类中名为TB_SayHi
控件(TextBlock
)的访问方法。.Text
是TextBLock
控件的属性,表示文本框中显示的文本内容。TB_SayHi().Text
表示访问该文本框的Text
属性。L"Hello World!"
是一个宽字符字符串,将文本框的内容设置为"Hello World!"
。因此,当按钮被点击时,TB_SayHi
文本块的内容被修改为"Hello World!"
。
应用 UI 主题色的修改位于App.xaml
标记文件下,增加代码RequestedTheme="Light"
实现,其代码如下,
<?xml version="1.0" encoding="utf-8"?>
<Application
x:Class="WinUI3Cpp.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:WinUI3Cpp"
RequestedTheme="Light">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
<!-- Other merged dictionaries here -->
</ResourceDictionary.MergedDictionaries>
<!-- Other app resources here -->
</ResourceDictionary>
</Application.Resources>
</Application>
10.3 C++/WinRT + WinUI3
10.3.1 数据绑定
• {x:Bind}
标记扩展
图10.7为{x:Bind}
标记扩展(markup extension)数据绑定的一个小示例。同前文默认应用,用程序模板Blank App, Packaged (WinUI 3 in Desktop)
(C++)创建项目,但项目名为WinUI3X
。每次点击按钮Click Me
,都会更新上方的数字,增加1。即,属性propertyValue
的初始值为 0
,通过数据绑定显示在 UI 的TextBlock
中,为初始状态;每次点击按钮,propertyValue
增加1,并通过Bindings->Update()
更新 UI。
图 10-7 {x:Bind}
标记扩展试验 App
文件 | MainWindow.xaml | MainWindow.xaml.h | MainWindow.xaml.cpp |
---|---|---|---|
代码 |
|
|
|
🤖 代码解读 |
这段 XAML 定义了一个简单的 WinUI3 窗口布局,其中包含一个
窗口功能:一个简单的窗口,包含一个绑定到属性 数据绑定:使用 |
这段代码定义了一个
成员变量和方法/函数: 用途:该代码是一个典型的 WinUI3 应用程序的后端框架,支持与前端 XAML 的数据绑定和交互。 |
这段代码是对
定义按钮点击事件的处理函数 属性机制: 按钮事件: 调试支持:通过 |
10.3.2 控件
• 控件(Controls)-事件处理
图10.8 用程序模板Blank App, Packaged (WinUI 3 in Desktop)
(C++)创建名为WinUI3X
的项目,移除了默认应用程序中按钮和属性部分的代码,从而在一个完全空的项目上构建应用。该示例应用包括两个部分,左部分是选择不同的单选按钮,变换圆形边框的颜色;右部分是在输入的文本框中输入名字等字符,点击Sy Hi!
按钮后会弹出对话框,显示消息。该部分展示了前端 UI 控件(XAML)和后端事件处理函数(C++/WinRT),表示与逻辑分离和交互实现的方式;也展示了winrt::fire_and_forget
和co_await
配合使用执行异步任务(操作)。
图 10-8 控件——事件处理
由 XAML 标记语言前端 UI 生成对应事件处理函数的后端代码(如示例中的 yellowButton_Checked 等在 .cpp 和 .h中的代码),可以将光标置于 XAML 的对应代码段内,按 F12 键自动生成。
更改 XAML 代码后,重构(Build Solution)应用程序,以便在.cpp代码中识别 XAML 元素。
文件 | MainWindow.xaml | MainWindow.xaml.h | MainWindow.xaml.cpp | MainWindow.idl |
---|---|---|---|---|
代码 |
|
|
|
|
🤖 代码解读 |
这段 XAML 代码定义了一个用户界面,包含一个圆形边框作为颜色展示面板,及单选按钮组和文本框按钮组合,用于与用户交互。
前端用户界面有三个部分,一个显示当前颜色的圆形面板;一个垂直排列的颜色选项按钮组;和一个输入框和按钮的组合,用于输入和触发事件。功能是,当选中不同颜色按钮时,触发 |
这段代码定义了
事件处理函数
事件处理:头文件定义了四个事件处理函数,分别响应单选按钮的选中事件和按钮的点击事件。 异步支持:提供了 |
定义异步方法
事件处理函数
|
在 IDL 文件中移除了默认应用中的 |
• 控件(Controls)-数据绑定
该部分应用示例展示了通过按钮点击更新下拉框数据集的三种数据关联方式。当点击各按钮Add Item
时,上方各自对应的下拉框会追加数据Item 1
、Item 2
等。虽然这三部分实现的功能一致,但是后端代码更新前端用户界面下拉框的数据方式不同,分别为手动列表管理(后端代码直接操作前端 UI 控件)、数据源绑定(后端代码绑定控件和数组变量)和数据绑定(前端 UI 绑定控件和数组变量(以获取器 getter 方式))的不同实现。
图 10-9 控件——数据绑定
文件 | MainWindow.xaml | MainWindow.xaml.h | MainWindow.xaml.cpp | MainWindow.idl |
---|---|---|---|---|
代码 |
|
|
|
|
🤖 代码解读 |
这段 XAML 代码定义了一个窗口,其布局由一个外层横向排列的
|
私有成员变量:
公有成员函数:
|
该部分代码主要定义了三个按钮的点击事件处理函数,通过直接(手动)操作、数据源绑定和 |
|
10.3.3 页面和导航
使用 WinUI3 创建一个包含多页面导航界面的应用程序。应用界面功能包括导航视图,为左侧垂直导航栏,提供主页面的导航入口,包括 Home(主页)、Other Page(其他页面)和 Settings(设置页面)。导航栏使用图标和文本直观展示页面导航选项,可折叠/展开;使用NavigationView
控件,具有现代化的响应式设计,支持多种窗口大小调整。右侧内容区域根据导航选项动态加载相应的页面内容,示例性的显示各自对应的文本。每个页面独立实现,通过Frame
控件加载,便于扩展和维护。位于左上角的后退按钮提供导航历史的回退功能,允许用户返回到前一个页面。如果用户在导航历史中没有可返回的页面则按钮禁用。
图 10-10 页面和导航
MainPage
、HomePage
、OtherPage
和SettingsPage
四个页面的创建方式为Solution Explorer->WinUI3X(Desktop)->右键弹出菜单->Add->New Item->Blank Page(WinUI3)
。其中页面的结构层次关系如图10.11,MainWindow
为应用程序的主窗口,作为程序启动后加载的初始窗口,主要任务是承载MainPage
。MainPage
作为应用程序的主页面,其包含一个Frame
(导航框架),用于显示和切换页面内容;NavigationView
控件用于导航到其它功能页面(如HomePage
、OtherPage
和SettingsPage
)。MainPage
是通过MainWindow
加载的。HomePage
、OtherPage
和SettingsPage
分别为MainPage
导航到的页面,为“主页”,“其他”功能页面和“设置“选项页面。项目结构中页面关系图的层级可以描述为MainWindow
包含MainPage
作为子页面;MainPage
通过NavigationView
和导航框架Frame
加载HomePage
、OtherPage
和SettingsPage
。
图 10-11 文件结构
1-MainWindow
在MainWindow.xaml
中,<local:MainPage/>
是一个自定义页面(或控件),其名字为MainPage
。并使用了自闭和标签/
,表示这是一个没有子元素的单独控件。local
是在根节点<Window>
中定义的一个命名空间前缀xmlns:local="using:WinUI3X"
,指向当前项目的命名空间WinUI3X
。作用是,所有前缀为local:
的控件或元素,均被解析为WinUI3X
命名空间内的类型。此处,local:MainPage
指向WinUI3X.MainPage
类。MainPage
自定义页面同样包括与之关联的 XAML 文件(MainPage.xaml
),描述其 UI 结构;一个后端代码文件(MainPage.xaml.cpp
,及其头文件MainPage.xaml.h
),描述行为逻辑;和 IDL 文件MainPage.idl
。
MainWindow
页面中,MainWindow.xaml.cpp
、MainWindow.xaml.h
和MainWindow.idl
中均移除了自动生成的按钮myButton
和属性变量MyProperty
相关部分的内容,保持为一个空白的页面。
在 WinUI 或类似框架中,将MainPage
嵌套到MainWindow
中是一种常见的设计模式,其目的是为了分离关注点和提升代码的可维护性,其优势有:
- 模块化设计。
MainWindow
的职责是作为应用的主要窗口,是整个应用的容器,主要负责窗口级别的设置,例如窗口标题;窗口尺寸和布局;应用程序的生命周期事件(如启动、最小化和关闭等)等。MainWindow
通常不直接承载复杂的 UI 内容,而是用来嵌套其他页面或控件。MainPage
的职责专注于应用程序的主要 UI 和交互逻辑。作为窗口的内容部分,定义了具体的用户界面(如按钮、输入框和列表等)。这种设计让界面逻辑和窗口设置分离,便于管理。 - 可扩展性。如果后续应用需要多页面导航(如从
MainPage
导航到SettingsPage
或其他页面),可以包含一个Frame
控件,用于托管不同的页面。这种设计使得应用具有更高的扩展性,而不是将所有内容直接嵌套到MainWindow
中。 - 简化代码结构。如果所有的 UI 和逻辑都写在
MainWindow
中,代码可能变得难以维护。将主要的 UI 放在MainPage
中,可以使每个类保持简洁,单一负责。 - 多窗口支持。可以在应用冲创建多个窗口,每个窗口可能有不同的内容,是独立的页面。
- 设计和开发分离。可以在设计阶段单独对页面进行布局和调整。在开发阶段,
MainWindow
和MainPage
以及其他页面的开发可以并行进行,提高效率。
文件 | MainWindow.xaml | MainWindow.xaml.h | MainWindow.xaml.cpp | MainWindow.idl |
---|---|---|---|---|
代码 |
|
|
|
|
2-MainPage
MainPage
通过MainWindow
加载,加载的代码为MainWindow.xaml
文件下的<local:MainPage/>
。而MainPage
通过NavigationView
控件导航到其他功能页面(HomePage
、OtherPage
和SettingsPage
)。
文件 | MainPage.xaml | MainPage.xaml.h | MainPage.xaml.cpp | MainPage.idl |
---|---|---|---|---|
代码 |
|
|
|
|
🤖 代码解读 |
该页面( |
此文件定义了一个 |
该部分空出。
以 该函数的功能就是使用主框架(
|
3-HomePage
、OtherPage
和SettingsPage
这三个页面均为演示性页面,页面内容除了在各自的 .xaml 文件中通过TextBlock
输出一段描述当前页的文本外,无其他功能,如<TextBlock Text="This is the HOME page." FontFamily="Arial" FontSize="24"/>
。
文件 | .xaml | .xaml.h | .xaml.cpp | .idl |
---|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10.3.4 文件选择器
该示例实现了通过点击Open file
按钮,打开文件浏览器,选择图片后,在窗口右侧显示该图片内容的功能。
图 10-12 文件选择器(打开的内部图片由 AI 生成器生成,工具 shakker,https://www.shakker.ai/home)
1-App
App.xaml
主要用于设置应用程序的全局资源和主题,定义了 UI 控件的资源字典(包括系统默认样式、控制资源等),并指定了应用程序的外观主题。在App.xaml
中,还可以设置应用启动时的一些行为,如启动窗口、全局样式等。这里增加了getMainWindow
方法,提供了一个方式来获取主窗口的原生句柄,便于与传统的 Win32 API 进行交互。
文件 | App.xaml | App.xaml.h | App.xaml.cpp |
---|---|---|---|
代码 |
|
|
|
🤖 代码解读 |
指定文档是 XML 格式,版本为 1.0,并使用 UTF-8 编码。
这段 XAML 是一个典型的 WinUI3 应用程序入口文件的模板,其定义了应用程序的根元素 |
这段代码是 WinUI3 应用程序的主要入口类 |
这段代码实现了一个简单的 WinUI3 应用程序,其中 |
2-MainWindow
MainWindow
页面中,MainWindow.xaml
、MainWindow.xaml.cpp
、MainWindow.xaml.h
和MainWindow.idl
中均移除了自动生成的按钮myButton
和属性变量MyProperty
相关部分的内容,保持为一个空白的页面。同页面和导航部分的MainWindow
,仅在MainWindow.xaml
中增加了<local:MainPage/>
一行代码,指向MainPage
页面。
3-MainPage
MainPage
通过MainWindow
加载,加载的代码为MainWindow.xaml
文件下的<local:MainPage/>
。MainPage
实现了用户点击按钮触发事件,加载图片文件到图片控件中显示的功能。
文件 | MainPage.xaml | MainPage.xaml.h | MainPage.xaml.cpp | MainPage.idl |
---|---|---|---|---|
代码 |
|
|
|
|
🤖 代码解读 |
定义用于显示图像的控件。 该部分 XAML 代码使用了网格布局将页面分为两列,一列置按钮;另一列置图片控件,显示用户选择的图像。当用户点击按钮触发事件,加载图片文件到图片控件中显示。 |
|
当按钮被点击时,调用
如果需要支持多种图片格式,可以修改文件类型过滤器,允许选择多种文件类型,如,
|
10.3.5 Sqlite 数据库和 ViewModel + UserControl
该部分示例包含用户信息数据录入、查看、编辑等功能,综合应用了 SQLite 数据库、ViewModel(视图模型)和 UserControl(用户控件)等技术。
*图 10-13 SQLite 读写数据库)
该项目文件结构主要包括:
- 应用程序核心部分(App):包含主应用入口文件(App.xaml)及其逻辑处理文件(后端代码)(App.xaml.cpp 和 App.xaml.h),负责应用程序的初始化和 UI 资源管理。
- 用户界面(UI):MainPage.xaml 和 MainWindow.xaml 分别定义了主页面和主窗口的 UI 布局。与之对应的 C++ 逻辑处理文件(如 MainPage.xaml.cpp、MainWindow.xaml.cpp)实现了页面的事件处理和功能逻辑。
- 用户控件(UserControl):UpdateUserControl.xaml 用于特定功能(如更新用户信息)的 UI 组件。相关的 C++ 文件(UpdateUserControl.xaml.cpp 和 UpdateUserControl.xaml.h)处理控件的事件和逻辑。
- 数据库支持(SQLite):sqlite3.c 和 sqlite3.h 包含 SQLite 数据库库文件,用于数据库的操作和管理。
- 视图模型(ViewModel):UserViewModel.idl 定义用户数据和视图逻辑的接口。相关的 C++ 实现文件(UserViewModel.cpp 和 UserViewModel.h)将 UI 和数据模型连接起来。
- 其他:Package.appxmanifest 配置应用程序的元数据,如权限、功能声明等。pch.cpp 和 pch.h 为预编译头文件,用于提高编译速度等。
该项目的结构清晰的分离了应用程序的各个模块,确保了 UI、业务逻辑、数据操作和视图模型之间的独立性和可维护性。核心逻辑与 UI 布局分开,使得项目可以方便地扩展和管理。
*图 10-13 SQLite 项目文件结构)
1-SQLite[sqlite3]
数据库
SQLite,是一个 C 语言实现的小型、快速、自包含(self-contained)、高可靠性、功能齐全的 SQL 数据库引擎。SQLite 被广泛使用,内置于电话和计算机中,并捆绑到无数人们日常使用的应用程序中。SQLite 文件格式稳定,跨平台且向后兼容,开发者承若在 2050 年之前都会保持这种状态。从 SQLite 官网下载sqlite-amalgamation-3480000.zip文件,解压后,复制sqlite3.c
和sqlite3.h
两个文件置于项目WinUI3App(Desktop)
新建的文件夹db
中(db 文件夹上右键->Add->Existing Item...->选择 sqlite3.c和sqlite3.h
)。
需要修改sqlite3.c
文件,删除/************** Begin file sqlite3.h *****************************************/
(第319行)到/************** End of sqlite3.h *********************************************/
(第 13941行)之间的内容;并通过搜索sqlite3_version
定位到下述代码,
#ifndef SQLITE_AMALGAMATION
/* IMPLEMENTATION-OF: R-46656-45156 The sqlite3_version[] string constant
** contains the text of SQLITE_VERSION macro.
*/
SQLITE_API const char sqlite3_version[] = SQLITE_VERSION;
#endif
将其中#ifndef SQLITE_AMALGAMATION
修改为#ifdef SQLITE_AMALGAMATION
。
同时修改该文件的两个属性,在sqlite3.c 文件上右键->Properties->C/C++->General->Warning Level
属性值修改为Level3(/W3)
;C/C++->Precompiled Headers->Precompiled Header
属性值修改为Not Using Precompiled Headers
。Warning Level
是 Microsoft C/C++ 编译器提供的一个设置,用于指定编译器在发生潜在问题时报告警告的详细级别。警告级别越高,编译器输出的警告信息越详细。Level3
过滤掉了不常见或影响较小的警告信息,避免开发者因过多的警告而忽略真正需要关心的问题,兼顾开发效率和代码质量。预编译头(Precompiled Header)是 C/C++ 编译优化的一种技术,用于加快项目的编译速度,是通过将一些不经常变化的头文件(如标准库、第三方库)预先编译成二进制文件,以便在后续的编译中直接使用,而无需每次都重新处理这些头文件(预编译头文件通常被命名为stdafx.h
或pch.h
)。而sqlite3.c
是单一源文件,并且是一个自包含的实现,不依赖外部头文件,因此使用预编译没有意义,反而可能引入编译错误(如缺少pch.h
)。而禁用预编译头可以简化编译过程,确保文件能够独立编译,并避免额外的配置和兼容性问题。
2-ViewModel[UserViewModel]
通过WinUI3App(Desktop)上右键->Add->New Item...->View Model(C++/WinRT)
建立ViewModel
(视图模型),命名为UserViewModel
,会自动生成三个文件UserViewModel.idl
、UserViewModel.h
和UserViewModel.cpp
。
ViewModel 是 MVVM (Model-View-ViewModle)设计模式中的一个重要概念,在软件开发中广泛应用,尤其开发带有图形用户界面的应用程序。ViewModel 充当了视图(View)与数据模型(Model)之间的桥梁,并且负责处理展示逻辑。MVVM 软件架构模式将应用程序分为三个主要部分:
- Model(模型):代表应用程序的核心数据和业务逻辑,通常独立于用户界面(UI),并负责数据存储、数据处理等操作。
- View(视图):代表用户界面部分,用于展示数据,通常是应用程序中的界面元素(如按钮、文本框、标签等)。
- ViewModel(视图模型):充当 Model 和 View 之间的中介,负责给管理显示数据并将其绑定到 View,同时处理用户交互,将数据从 Model 转换为适合 View 显示的格式。
ViewModel 使得视图和模型之间的依赖关系降到最低。视图无需直接操作数据模型,也不需要知道模型的具体实现。ViewModel负责将数据传递到视图,并根据需要更新模型。ViewModel 与 View 之间的绑定,
- 数据绑定: 视图(View)通过数据绑定将 ViewModel 的属性连接到 UI 控件(如文本框、标签、按钮等)。
- 命令绑定:视图通过命令(如按钮点击)来触发 ViewModel 中的方法。
MVVM 的优点,
- 清晰的分离职责:MVVM 模式将 UI 和应用程序逻辑分开,帮助实现代码的清晰分离,便于维护和扩展。
- 可测试性:由于 ViewModel 是纯粹的逻辑层,与 UI 无关,因此容易进行单元测试。
- 灵活的 UI 更新:ViewModel 可以独立于视图进行更新,且支持响应式数据绑定,UI 可以根据数据的变化自动更新。
文件 | UserViewModel.idl | UserViewModel.h | UserViewModel.cpp |
---|---|---|---|
代码 |
|
|
|
🤖 代码解读 |
定义了四个只读属性:
|
通过私有成员变量存储用户数据为数据封装;通过公共方法提供对数据的访问和修改为接口暴露。 |
|
3-Database[DbHelper]
用于封装 SQLite 数据库针对用户数据处理的常用操作,如打开、关闭数据库,检索、插入、更新和删除数据等。
文件 | DbHelper.h | DbHelper.cpp |
---|---|---|
代码 |
|
|
🤖 代码解读 |
这段代码定义了
|
这段代码是
该函数尝试打开一个 SQLite 数据库。如果打开成功,检查是否存在名为
-编译 SQL 语句。使用
-绑定参数。使用
-执行语句。使用
-是否资源。使用
该函数的功能是从
使用数据库自增功能替代手动管理 ID,避免冲突(并发控制),如,
如果手动管理 ID,考虑在程序内维护一个计数器变量,减少频繁的查询(优化性能),如,
当前实现逻辑简单可靠,适合小型应用和低并发场景。如果需要处理高并发或大数据场景,推荐改用 SQLite 的
该函数从数据库中查询所有用户数据,并将每个用户的数据存储到
函数定义。
初始化变量。
SQL 查询语句选择。
根据
预处理 SQL 查询。
绑定 SQL 参数。
将
执行查询。
结束 SQL 语句。
返回结果。
该函数用于更新或插入用户数据到数据库的
该函数用于删除
这个转换函数在处理从数据库查询返回的字节数据(如文本数据)是非常有用,尤其是在需要将这些数据转换为 Windows 应用程序能够理解和处理的字符串类型时。 |
4-App
该示例中,App
包含DbHelper
类的定义文件,并声明和定义了DbHelper
类的静态成员变量db
,作为应用程序的全局数据库工具。
文件 | App.xaml | App.xaml.h | App.xaml.cpp |
---|---|---|---|
代码 |
|
|
|
🤖 代码解读 |
|
|
|
5-MainWindow
在MainWindow
中嵌入MainPage
页面,主要目的是为了实现职责分离和模块化设计,从而提高代码的可读性、可扩展性和可维护性。
文件 | MainWindow.xaml | MainWindow.xaml.h | MainWindow.xaml.cpp | MainWindow.idl |
---|---|---|---|---|
代码 |
|
|
|
|
🤖 代码解读 |
|
6-UserControl[UpdateUserControl]
通过WinUI3App(Desktop)上右键->Add->New Item...->User Control(WinUI3)
建立UserControl
(用户控件),命名为UpdateUserControl
,会自动生成4个文件UpdateUserControl.xaml
、UpdateUserControl.idl
、UpdateUserControl.h
和UpdateUserControl.cpp
。UserControl
允许开发者将多个控件和功能组合在一起,形成一个新的复合控件,方便在项目中重复使用和维护。
文件 | UpdateUserControl.xaml | UpdateUserControl.xaml.h | UpdateUserControl.xaml.cpp | UpdateUserControl.idl |
---|---|---|---|---|
代码 |
|
|
|
|
🤖 代码解读 |
这个 XAML 文件定义了一个名为
|
这个结构体
此外,控件的事件处理程序可以通过 |
这段代码是
这个方法的作用是向
|
IDL(Interface Definition Language)文件,用于描述 Windows Runtime 组件的接口、类、事件和数据类型。这里定义了一个 Windows Runtime 类 |
7-MainPage
嵌套于MainWindow
中的MainPage
包含应用程序的主要 UI 和交互逻辑。
文件 | MainPage.xaml | MainPage.xaml.h | MainPage.xaml.cpp | MainPage.idl |
---|---|---|---|---|
代码 |
|
|
|
|
🤖 代码解读 |
|
|
|
SQLite 数据库保存在了类似C:\Users\richie\AppData\Local\Packages\300da4f9-d702-4a8e-b3e0-b320da8596e0_5zfe55br6hb1t\LocalState\database.db
的文件路径下。可以用DB Browser for SQLite辅助查看数据库中存储的数据内容。
图 10-14 用 DB Browser for SQLite 查看数据库
10.3.6 UI 动画
该示例应用界面显示了一个联系人列表,包括姓名和国家。并配置了鼠标指针进入和离开联系人项上时的交互动画效果(放大等),使得 UI 更加动态,互动性增强。
图 10-15 动画效果
1-App
在创建动画和视觉效果时,Compositor
(位于winrt::Microsoft::UI::Xaml::Window
类型下)提供了许多方法来创建和管理动画,通过static winrt::Microsoft::UI::Xaml::Window window;
(App.xaml.h)和winrt::Microsoft::UI::Xaml::Window App::window{ nullptr };
(App.xaml.cpp)将window
配置为静态成员,可以轻松的在应用的任何地方访问窗口的Compositor
,进而创建和管理动画效果。
文件 | App.xaml | App.xaml.h | App.xaml.cpp |
---|---|---|---|
代码 |
|
|
|
🤖 代码解读 |
|
|
|
2-ContactViewModel
ContactViewModel
类用于表示和管理一个联系人的信息,包括名称(Name)和国家(Country);并实现了获取联系人数据的属性(Name
和Country
),提供了设置这些数据的一个方法SetContactData
。ContactViewModel
类是典型的视图模型(ViewModel)类,通过数据绑定与 XAML 视图交互,更新和显示数据。
文件 | ContactViewModel.idl | ContactViewModel.h | ContactViewModel.cpp |
---|---|---|---|
代码 |
|
|
|
🤖 代码解读 |
该 IDL 文件定义了 |
|
这段代码是 |
3-MainWindow
将MainPage
嵌套到MainWindow
中,让界面逻辑和窗口设置分离,便于管理。删除自动生成的按钮和属性等代码行,在MainWindow.xaml
中增加一行<local:MainPage/>
代码,实现窗口嵌套。
4-MainPage
用于应用程序的主要 UI 和交互逻辑,为窗口的内容部分,定义具体的用户界面。
文件 | MainPage.xaml | MainPage.xaml.h | MainPage.xaml.cpp | MainPage.idl |
---|---|---|---|---|
代码 |
|
|
|
|
🤖 代码解读 |
这段 XAML 代码定义了一个 |
|
该方法创建了多个
|
10.3.7 网络
该示例是点击按钮Request
,向指定的网址(API)发起一个网络请求,获取 JSON 格式的数据,解析并显示在应用界面上。
图 10-16 网络请求
1-MainPage
文件 | MainPage.xaml | MainPage.xaml.h | MainPage.xaml.cpp | MainPage.idl |
---|---|---|---|---|
代码 |
|
|
|
|
🤖 代码解读 |
这个页面包含一个水平排列的布局(
|
|
这段代码是
异常捕获 如果
清理操作
|
10.4 C# + WinUI3
10.4.1 默认应用(C#)代码解读和 Hello world!
10.4.1.1 默认应用(C#)代码解读
打开 VS->Create a new porject
时,选择语言类型(languages)为 C#,选择的项目类型为WinUI
,在列出的项目模板中选择Blank App, Packaged(WinUI 3 in Desktop)
[C#、XAML、Windows、Desktop、WinUI],建立项目,默认的应用界面如图 10-17,与前文建立的 C++ 默认应用结果相同。
图 10-17 C# 默认应用示例
与使用 C++/WinRT 的 WinUI 3 项目相比(图10-18),使用 C# 的 WinUI 3 项目的文件结构要简洁。对于一个页面(窗口),如MainWindow
, C++/WinRT 包含有 4 个文件,为一个标记文件MainWindow.xaml
和一个 C++/WinRT 代码文件MainWindow.xaml.cpp
,及其对应的头文件MainWindow.xaml.h
,及MainWindow.idl
IDL 文件;而 C# 只包含 2 个文件,为一个标记文件MainWindow.xaml
,和一个 C# 代码文件MainWindow.xaml.cs
。
图 10-18 C# 和 C++/WinRT 默认应用项目文件结构
在 WinUI3 中,App
和MainWindow
是两个核心类,分布负责应用程序的生命周期管理和主窗口的界面呈现。
1-App
App
类是整个应用程序的入口点,继承自Microsoft.UI.Xaml.Application
类,主要作用包括:生命周期管理(处理应用程序的启动、挂起、恢复等事件(如OnLaunched
);在应用启动时创建主窗口并启动用户界面),初始化(加载应用程序的资源(如 XAML 资源字典);执行全局的配置和初始化代码),全局对象管理(提供一个应用级别的上下文,允许共享全局状态和数据)。
文件 | App.xaml | App.xaml.cs |
---|---|---|
代码 |
|
|
🤖 代码解读 |
|
这段代码实现了一个 WinUI3 应用程序的基本框架。从 |
2-MainWindow
MainWindow
是应用程序的主窗口,继承自Microsoft.UI.Xaml.Window
,主要作用包括:用户界面承载(显示应用程序的主界面,通常由一个 XAML 文件定义其布局;包含用户控件、按钮、文本框等元素,用于实现交互功能),事件处理(定义界面控件的交互逻辑(如按钮点击事件、输入事件)),窗口管理(设置窗口的标题、大小、布局等属性;可以在窗口内导航到其他页面或管理多个子窗口)。
文件 | MainWindow.xaml | MainWindow.xaml.cs |
---|---|---|
代码 |
|
|
🤖 代码解读 |
MainWindow.xaml 文件与 C++/WinRT 中定义的 MainWindow.xaml 文件代码基本相同,此处不再赘述。 |
这段代码包含几个关键信息:
|
10.4.1.2 Hello world!
C# 版的 Hello world! 与 C++/WinRT 版的 Hello world! 除了后端代码一个用 C# 实现,一个用 C++/WinRT 实现,各自所对应的文件MainWindow.xaml.cs
和MainWindow.xaml.cpp
存在差异外,其他内容基本保持一致,如在App.xaml
标记文件中增加RequestedTheme="Light"
,将应用界面主题色修改亮色模式;在MainWindow.xaml
中调整按钮Button
的样式,并增加文本块TextBlock
控件等。
图 10-19 Hellow world! (C#版)
文件 | MainWindow.xaml | MainWindow.xaml.cs |
---|---|---|
代码 |
|
|
🤖 代码解读 |
|
10.4.2 WinUI 3 Gallery
WinUI3 是原生 UI 平台组件,随 Windows 应用程序 SDK(Windows App SDK(Software Development Kit,软件开发工具包)) 一起发布,并与其完全解耦。Windows App SDK 提供了一套统一的 APIs 和工具,可用于创建针对 Windows 10 及更高版本生产桌面的应用程序,并可以发布到微软的应用商店中。为了使开发者快速的了解、掌握 WinUI 3, 并有助于开发者快速开始开发自己的项目,微软公司开发了WinUI 3 Gallery应用程序(图 10-20),演示了所有的 WinUI 3 中的控件和样式(用 Windows App SDK 制作 WinUI 3 应用程序)。并提供了 WinUI 3 Gallery 应用程序的源码,极大方便了开发者对 WinUI 3 的学习,和对控件的应用,且可直接代码迁移于开发者正在开发的项目,加快开发的速度、提升开发的效率。
图 10-20 WinUI 3 Gallery
- 用 WinUI 3 Gallery 辅助构建应用示例
学习 WinUI 3(C#) 的一种非常有效的方法是通过 WinUI 3 Gallery 示例应用。WinUI 3 Gallery 应用展示了 WinUI 3 的各种功能、控件和样式,可以帮助开发者快速理解如何在实际项目中使用这些功能。图10-21 为集合了 WinUI 3 Gallery 应用中的 7 个典型的布局和控件示例完成的应用结果。这几个布局或控件包括 NavigationView(Navigation)、MenuBar(Menus & toolbars)、SelectorBar(Navigation)、CommandBar(Menus & toolbars)、Scratch Pad(System)、WebView2(Media)和 GridView(Collection)。在应用 WinUI 3 Gallery 学习布局或控件时,在应用中的每个主题示例中均给出了对应示例的代码,并在每页的顶部给出了对应的文档链接(Documentation)和托管于 GitHub上 XAML 和 C#的源码(Source)链接。
图 10-21 实例应用(C#)(Selector Bar 下 Grid View 中使用的图片来自于 AI 图片生成,包括 ChatGPT、Google Gemini、Ahakker)
构建该示例应用时,采用了MainWindow
嵌套MainPage
的设计模式。并将布局或控件的示例置于SamplePages
文件夹下,具体项目文件结构如图10-22。
图 10-22 项目文件结构
本部分应用示例因为代码相对较多,并且迁移于 WinUI 3 Gallery 应用,因此读者可以直接学习 WinUI 3 Gallery 对应的布局或控件部分源码,或者从coding-x 下载。下述仅对该示例应用主要的代码部分进行解释。
1-MainPage
导航主页面。包含的导航视图控件通过一个可折叠的导航菜单为应用程序的顶层区域提供了一个通用的垂直布局。
文件 | MainPage.xaml | MainPage.xaml.cs |
---|---|---|
代码 |
|
|
🤖 代码解读 |
这段 XAML 定义了一个包含文本和导航菜单的页面。页面使用了
|
|
2-MenuBar
MenuBar
通过在应用程序或窗口的顶部提供一组菜单,简化了基本应用程序的创建。
文件 | MenuBar.xaml | MenuBar.xaml.cs |
---|---|---|
代码 |
|
|
🤖 代码解读 |
这段 XAML 定义了一个包含菜单栏的页面,菜单栏包含多个菜单项(如
|
这段 C# 代码是 WinUI 3 中
|
3-CommandBar
命令栏(Command bars)使用户可以轻松访问应用程序中最常见的任务。命令栏可以提供对应用级或特定于页面的命令的访问,可以与任何导航模式一起使用。默认情况下,命令栏显示一行图标按钮和一个可选的由[...]
省略号表示的“查看更多(see more)”按钮。
文件 | CommandBar.xaml | CommandBar.xaml.cs |
---|---|---|
代码 |
|
|
🤖 代码解读 |
这段代码定义了一个包含
|
这两个方法控制一个名为
用于处理一个
该方法将多个
这三个方法组合实现了移除
此方法为
|
4-ScratchPad
提供了一个编辑框,在其中键入 XAML 标记代码,加载后可以查看其外观和行为。
该部分的内容可以详细查看 WinUI 3 Gallery 中对应 Scratch Pad 的解释,并从该页面的顶部查看文档和源码(XAML 和 C#)。
5-WebView2
一个基于 Microsoft Edge(Chromium)的控件,在应用程序中托管 HTML 内容。
文件 | WebViewToPage.xaml | WebViewToPage.xaml.cs |
---|---|---|
代码 |
|
|
🤖 代码解读 |
|
6-GridView
+ ViewMOdel
允许显示按水平滚动的行和列排列的项目集合。
文件 | GridView.xaml | GridView.xaml.cs |
---|---|---|
代码 |
|
|
🤖 代码解读 |
这段 XAML 代码展示了如何使用
|
该方法在导航到该页面时被触发,用于初始化数据并设置页面的内容。
|
文件 | ViewModel.xaml | ViewModel.xaml.cs |
---|---|---|
代码 |
|
|
🤖 代码解读 |
这段代码定义了一个
|
10.5 打包和发布应用
10.5.1 打包配置(应用程序配置清单)
在Solution Explorer
下的Package.appxmanifest
文件,其选项卡参数的配置有关应用程序的元数据、设置和声明信息,用于定义应用的基本信息及如何与操作系统交互。
- Application 选项卡主要用于配置识别和描述应用程序的属性。
图 10-23 Application 选项卡
Display name
(显示名称):用于定义应用程序的显示名称。Entry point
(入口点):指定应用程序启动时的入口点,一般是主类或程序集的名称。当前值为$targetentrypoint$
,表示为一个占位符,会在应用构建时替换为具体的入口点。Default language
(默认语言):设置应用程序的默认语言。与清单配置器中大多数字段不同,此值保存在项目文件中,而不是应用程序清单中。Description
(描述):描述应用程序的功能或用途,是指定在Set Default Programs
界面中显示的文本。Trust level
(信任级别):配置应用程序的信任级别。取值为AppContainer
或MediumIL
。试验中为(not set)
,未设置。Runtime behavior
(运行时行为):定义应用程序运行时行为,取值为WindowsApp
、PackageClassApp
、Win32App
或AppSilo
。试验中为(not set)
,未设置。Supported rotations
(支持的屏幕旋转):一个可选的配置,指示应用程序的方向偏好,包括Landscape
(横向)、Portrait
(纵向)、Landscape-flipped(横向翻转)
和Portrait-flipped
(纵向翻转)。实验中选择了Landscape
和Portrait
。Lock screen notifications
(锁屏通知):配置程序在用户锁屏屏幕上显示通知的方式。包含的值有Badge
或BadgeAndTileText
。试验中为(not set)
,未设置。Resource group
(资源组):一个应用程序定义的名称,用于确定多个任务的相同主机进程。Tile Upate
(磁贴更新):通过定期轮询 URI (Uniform Resource Identifier,统一资源标识符)更新应用程序标题。URI 模板可以包含language
和region
令牌(tokens),这些令牌将在运行时被替换,以生成要轮询的 URI。URI Template
(URI 模板):指定用于在应用程序首次启动之前开始更新该应用程序标题的 URI。
- Visual Assets 选项卡用于生成和配置应用程序不同分辨率的视觉资源,确保应用在各种显示设备上都能正确展示图标和启动画面。
图 10-24 Visual Assets 选项卡
Asset Generator
(资源生成器)
Source
(源文件):选择用于应用程序图标的图像。Destination
(目标文件夹):设置生成的资源文件存放的目标文件夹。这里按默认为Assets
。Assets
(资源类型):选择生成的资源类型,例如小图标(Small Tile)、中等图标(Large Tile)、应用图标(App Icon)、启动画面(Splash Screen)等。Scales
(缩放比例):选择资源的缩放比例。Scaling Mode
(缩放模式):选择图像缩放的方式,包括Bicubic(Smoother Edges)
和Nearest Neighbor(Sharper Edges)
。Apply recommended padding
(应用推荐的填充):选择是否应用建议的图像填充。Apply color conversion for Windows Light Theme
(应用 Windows Light Theme 的颜色转换):选择是否为 Windows Light Theme(浅色主题)进行颜色转换。Generate
(生成):点击按钮来生成所需的所有图像资源。
Display Settings
(显示设置)
Short name
(短名称):应用程序的缩写名称。Show name
(显示名称):选择在磁贴中显示名称的类型,可以选择Medium Tile
、Wide Tile
或Large Tile
。Tile background
(磁贴背景):设置磁贴的背景颜色或透明度。这里设置为transparent
(透明)。Splash screen background
(启动画面背景):设置启动画面的背景颜色。
Preview Images
(预览图像)
显示源图像及其缩放版本的预览图。这些缩放后的图像用于不同尺寸的磁贴显示。
- Capabilities 选项卡用于设置应用程序需要使用的系统功能或设备权限。
图 10-25 Capabilities 选项卡
可以通过点击Capabilities
列表框中的各项,在Description
下会对应给出所选项的解释说明。
- Declarations 选项卡可添加声明并指定其属性
图 10-26 Declarations 选项卡
打开Available Declarations
(可用声明)下拉框,可以看到支持的声明,包括有Account Picture Provider
(账户图片提供程序)、Alarm
(闹钟)、App Extension Host
(应用程序扩展主机)、App Service
(应用程序服务)、Appointments Provider
(约定提供程序)、AutoPlay Content
(自动播放内容)、AutoPlay Device
(自动播放设备)、Background Tasks
(后台任务)、Cached File Updater
(缓存文件更新程序)、Camera Settings
(相机设置)、Certificates
(证书)、Dial Protocol
(拨号协议)、File Open Picker
(文件打开选择器)、File Save Picker
、File Type Associations
(文件类型关联)、Lock Screen
(锁屏)、Media Playback
(媒体回放)、Personal Assistant launcher
(个人助理启动)、Pre-installed Configuration
(预安装配置)、Print 3D Workflow
(3D 打印工作流)、Print Task Settings
(打印任务设置)、Protocol
(协议)、Restricted Launch
(受限启动)、Search
(搜索)、Share Target
(共享目标)。
这些声明帮助开发者定义应用程序的功能和与操作系统集成方式,以便更好地利用 Windows 平台的特性和服务。
- Content URIs 选项卡指定可以使用
window.external.notify
向应用程序发送ScriptNotify
事件的 URIs。
图 10-27 Content URIs 选项卡
URIs 可以在子域名中包含通配符,如https://*.microsoft.com
或 https://*.*.microsoft.com
。
- Packaging 选项卡设置应用程序的打包信息,即设置应用程序包在部署时的标识(identify)和描述(describe)属性。
图 10-28 Packaging 选项卡
Package name
(包名称):指定在系统上标识包的唯一名称。当包上传到商店时,此名称将被替换。示例使用默认生成的名称。Package display name
(包显示的名称):指定出现在应用商店中的应用程序名称。当包上传到商店时,此名称将被替换。示例中使用的名称为WinU3CSharp
。Version
(版本):一个四元表示法的版本字符串,Major.Minor.Build.Revision
。Publisher
(发布者):应用程序的发布者信息。指定用于对包进行身份验证的签名证书的主题字段。当包上传到商店时,此名称将被替换。(证书在Create App Packages...
时配置,见后文)Publisher display name
(发布者显示名称):指定在开发人员门户网站上的“Publisher Name”字段上使用的名称。当软件包上传到 Windows App Store 时,此名称将被替换。Package Family name
(包家族名称):标识系统上包的唯一名称,由包名称和发布者字符串的散列(hash)组成。
10.5.2 创建应用程序包
在Solution Explorer
(解决方案资源管理器)项目名称(示例的项目名称为WinUI3CSharp
)上右键菜单栏选择Package and Publish->Create App Packages...
创建应用程序包。
- 步骤1:Select distribution method
图 10-29 Select distribution method
可以选择的部署方式包括官方渠道Microsoft Store
(微软商店),和第三方渠道Sideloading
。Sideloading
(侧载)是指安装来自非官方渠道的应用程序,以创建自己的应用,包括企业应用程序(line-of-business,LOB)。当侧载应用程序时,需将签名的应用程序包(signed app package)部署到安装的设备上,并维护应用程序的签名、托管和部署。并且只有将分配给应用程序的受信任安全证书导入到本地设备,以允许设备信任该应用程序。
- 步骤2:Select signing method
图 10-30 Select signing method
应用程序包只有签名(signed)才能在设备上安装。选择证书对应用程序包进行签名的证书选择包括从Azure密钥库;从应用商店;从文件;或自行创建(Create
)。当选择创建将进入创建自签名测试证书弹出框(Create a Self-Signed Test Certificate
)。自签名证书通常用于测试,当安装到其他设备上可能会受到限制。填写发布者通用名称(Publisher Common Name
)和密码后返回Select signing method
弹窗,并显示了当前所用的证书。
- 步骤3:Select and configure packages
图 10-31 Select and configure packages
选择输出应用程序包的存储位置,配置应用版本,选择架构(Architecture)和解决方案配置(Solution Configuration)后开始创建(Create
)应用程序包。创建完成后,打开输出路径文件夹,点击*.cer
文件安装证书后,通过双击*.msix
文件安装应用;或右键点击Add-AppDevPackage.ps1
文件,从弹出菜单中选择Run with PowerShell
执行安装。完成安装后,就可以从系统的开始菜单中找到已安装的应用或搜索应用,打开应用,运行、调试和测试应用程序包,可以使用 Windows 调试工具调试应用程序。
参考文献(Reference):
[1] Overview of framework options (https://learn.microsoft.com/en-us/windows/apps/get-started/?tabs=cpp-win32%2Cpwa).
[2] XAML overview (https://learn.microsoft.com/en-us/windows/uwp/xaml-platform/xaml-overview).
[3] Fluent 2 (https://fluent2.microsoft.design/get-started/whatisnew).
[4] WinUI in the Windows App SDK (WinUI 3) (https://learn.microsoft.com/en-us/windows/apps/winui/winui3/).
[5] Build a Hello World app using C# and WinUI 3 / Windows App SDK(https://learn.microsoft.com/en-us/windows/apps/how-tos/hello-world-winui3).
[6] C++/WinRT+WinUI (https://www.youtube.com/@Tothepoint-uw3ws/playlists).
[7] Package a desktop or UWP app in Visual Studio(https://learn.microsoft.com/en-us/windows/msix/package/packaging-uwp-apps).