WinUI 应用中的窗口功能由 XAML Window 类和 AppWindow 类的组合提供,这两者都基于 Win32 HWND 模型。
- 重要 API: Window 类、 AppWindow 类
WinUI 3 示例集应用程序包括大多数 WinUI 3 控件、特性和功能的交互式示例。 通过 Microsoft Store 获取应用,或在 GitHub 上获取源代码
XAML Window
在应用中,window 对象是表示程序代码中的窗口的 Microsoft.UI.XamlWindow 类(或派生类)的实例。 使用对构造函数的调用直接创建它。 在 XAML Window 中,你可以附加应用内容并管理应用窗口生命周期。
HWND
应用程序窗口由Windows作系统创建,由 Win32 窗口对象表示。 这是一个由系统管理的容器,用于托管您的内容,并表示当用户调整应用大小或在屏幕上移动应用时与之交互的实体。 (有关详细信息,请参阅 Win32 文档中的 “关于 Windows ”。)
Windows 创建应用程序窗口后,创建函数将返回一个唯一标识窗口的 window handle (HWND)。 A window handle 具有 HWND 数据类型,尽管它在 C# 中显示为 IntPtr。 它是不透明的句柄,指向一个内部 Windows 数据结构,该结构对应于由操作系统绘制且存在时会消耗系统资源的窗口。
HWND 是在 XAML Window 对象之后被创建的,通常是在调用 Window.Activate 方法时。
AppWindow
Windows应用 SDK 通过 Microsoft.UI.Windowing 类提供其他开窗功能。AppWindow AppWindow 表示 HWND 的高级抽象。 应用中的 AppWindow 与顶级 HWND 之间存在 1:1 映射关系。 AppWindow 及其相关类提供 API,让你无需直接访问 HWND 即可管理应用的顶级窗口的许多方面。
对象的生存期 AppWindow 和 HWND 是相同的,即 AppWindow 在创建窗口后立即可用;当窗口关闭时会销毁它。
窗口 API 图示
此图显示了用于管理应用中窗口的类和 API 之间的关系,以及哪些类负责窗口管理的每个部分。 在某些情况下,例如 ExtendsContentIntoTitleBar,API 是 AppWindow 的一个成员,因此可以供其他 UI 框架使用,但为了方便起见,该 API 也会在 Window 类中公开。 该图并不全面,但显示了最常用的 API。
Note
可以使用AppWindow API 与 Windows 应用 SDK 支持的任何 UI 框架配合 - Win32、WPF、WinForms 或 WinUI 3。 对于 WinUI 3 以外的框架,关系图的 XAML Window 框中显示的功能将由框架特定的恰当窗口 API 替换:
Window/AppWindow API 比较
如果使用 WinUI 3 XAML 作为应用的 UI 框架,那么 Window 和 AppWindow 两个 API 都可以使用。 从 Windows App SDK 1.4 开始,可以使用 Window.AppWindow 属性从现有 XAML 窗口获取 AppWindow 对象。 使用此 AppWindow 对象可以访问其他窗口管理 API。
Important
如果未使用 WinUI 3 1.3 或更高版本,请通过互操作 API 获取 AppWindow,以便使用 AppWindow API。 有关互操作 API 的详细信息,请参阅管理应用窗口 - UI 框架和 HWND 互操作以及窗口化库示例。
生存期管理
| XAML Window | AppWindow |
|---|---|
| Constructor | Create、 GetFromWindowId |
| Activate | 显示、 隐藏 |
| Close、 Closed | 销毁、 销毁、 关闭 |
| >>> | Id、 OwnerWindowId |
在 Visual Studio 中创建新的 WinUI 项目时,项目模板会为你提供一个 MainWindow 类,该类是子 Window类。 如果你的应用只需一个窗口,这样就够了。 若要了解如何创建和管理其他窗口,以及你可能想要的原因,请参阅 应用显示多个窗口。
该 AppWindow 类具有用于创建和销毁新窗口的 API;但是,对于 WinUI 应用,实际上不会执行此作,因为没有 API 可将内容附加到所创建的窗口。 相反,你会获得一个由系统创建并与 XAML AppWindow 和 HWND 相关联的 Window 实例。 在 WinUI 1.4 及更高版本中,可以使用 Window.AppWindow 属性获取 . 的 AppWindow实例。 在其他情况下,可以使用静态 AppWindow.GetFromWindowId 方法来获取 AppWindow 实例。 有关详细信息,请参阅 “管理应用”窗口 。
Content
| XAML Window | AppWindow |
|---|---|
| Content | N/A |
Window内容 属性是用于将应用程序内容附加到显示它的窗口的位置。 可以在 XAML 或代码中执行此作。
标题、图标和标题栏
| XAML Window | AppWindow |
|---|---|
| Title | Title |
| SetTitleBar | TitleBar |
| >>> | SetIcon、 SetTaskbarIcon、 SetTitleBarIcon |
| ExtendsContentIntoTitleBar | AppWindow.TitleBar.ExtendsContentIntoTitleBar |
可以不同程度地修改应用的标题栏;设置标题和图标、更改颜色或完全将标题栏替换为自定义应用内容。
有关使用标题栏 API(包括代码示例)的信息,请参阅 标题栏自定义。
大小和位置
| XAML Window | AppWindow |
|---|---|
| Bounds | Position、 Size、 ClientSize |
| SizeChanged | 已更改(DidPositionChange、DidSizeChange) |
| >>> | Move、 Resize、 ResizeClient、 MoveAndResize |
| >>> | MoveInZOrderAtBottom、 MoveInZOrderAtTop、 MoveInZOrderBelow |
您可以使用 Window.Bounds 属性和 SizeChanged 事件来管理应用程序的用户界面,例如在窗口大小变化时移动元素。 XAML 使用 effective pixels (epx),而不是实际的物理像素。 Effective pixels 是一个虚拟度量单位,用于表示布局尺寸和间距,与屏幕密度无关。
AppWindow另一方面,使用 Window 坐标系,其中基本度量单位是物理 设备像素。 你可以使用 AppWindow API 进行窗口化操作,例如调整窗口大小或移动窗口相对于屏幕上其他内容的位置。
在某些情况下,您可能需要在一个类中使用另一个类的度量值,此时您需要在 effective pixels 和设备像素之间进行转换。 例如,如果在自定义标题栏中设置拖动区域,则需要转换度量值。 有关如何使用 XamlRoot.RasterizationScale 转换度量的示例,请参阅标题栏自定义文章的交互式内容部分。
外观和行为
| XAML Window | AppWindow |
|---|---|
| SystemBackdrop | N/A |
| >>> | 演示者,SetPresenter |
| >>> | IsShownInSwitchers |
| 可见, VisibilityChanged | IsVisible、已更改 (DidVisibilityChange) |
| DispatcherQueue | DispatcherQueue、 AssociateWithDispatcherQueue |
| Compositor | N/A |
XAML Window API 通常负责应用内容的外观,例如背景。 有关 SystemBackdrop 的详细信息,请参阅 使用 Mica 或 Acrylic 材料。
AppWindow API 负责窗口 的非客户端 部分以及应用与 Windows OS 的交互。
Note
XAML Window 类具有多个从 UWP Windows.UI.Xaml.Window 类继承的属性,但在 WinUI 应用中不支持。 这些属性始终具有值 null ,并且不在 WinUI 应用中使用: CoreWindow、 Current和 Dispatcher。
跟踪当前窗口
尽管 WinUI 应用中不支持该 Current 属性,但仍可能需要从应用中的其他地方访问 Window API。 例如,你可能需要从 Window 代码中获取 Window 边界或处理 .SizeChanged 事件。 在这种情况下,可以通过在Window类上使用公共静态属性,类似于Current属性的方式,提供对App的访问权限。
为此,请修改 Window App 类中的声明,如下所示。
// App.xaml.cs in a WinUI app
public partial class App : Application
{
...
public static Window Window { get { return m_window; } }
private static Window m_window;
}
// App.xaml.h in a WinUI app
...
struct App : AppT<App>
{
...
static winrt::Microsoft::UI::Xaml::Window Window(){ return window; };
private:
static winrt::Microsoft::UI::Xaml::Window window;
};
...
// App.xaml.cpp
...
winrt::Microsoft::UI::Xaml::Window App::window{ nullptr };
...
然后,若要访问 Window 应用中的其他位置,请使用 App.Window,如下所示:
// MainPage.xaml.cs in a WinUI app
var width = App.Window.Bounds.Width;
// MainPage.xaml.cpp in a WinUI app
#include <App.xaml.h>
auto width{ App::Window().Bounds().Width };
Important
如果应用仅使用单个窗口,则使用类中的Window静态App属性非常有用。 如果应用使用多个窗口,则应使用 WindowId 来跟踪 Window 实例,以确保访问正确的实例 Window。 有关详细信息和示例,请参阅 应用显示多个窗口 。