WinUI 和 Windows 应用 SDK 的窗口概述

WinUI 应用中的窗口功能由 XAML Window 类和 AppWindow 类的组合提供,这两者都基于 Win32 HWND 模型

WinUI 3 示例集应用程序包括大多数 WinUI 3 控件、特性和功能的交互式示例。 通过 Microsoft Store 获取应用,或在 GitHub 上获取源代码

XAML Window

在应用中,window 对象是表示程序代码中的窗口的 Microsoft.UI.XamlWindow 类(或派生类)的实例。 使用对构造函数的调用直接创建它。 在 XAML Window 中,你可以附加应用内容并管理应用窗口生命周期。

HWND

应用程序窗口由Windows作系统创建,由 Win32 窗口对象表示。 这是一个由系统管理的容器,用于托管您的内容,并表示当用户调整应用大小或在屏幕上移动应用时与之交互的实体。 (有关详细信息,请参阅 Win32 文档中的 “关于 Windows ”。)

Windows 创建应用程序窗口后,创建函数将返回一个唯一标识窗口的 window handleHWND)。 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。

WinUI 窗口化图

Note

可以使用AppWindow API 与 Windows 应用 SDK 支持的任何 UI 框架配合 - Win32、WPF、WinForms 或 WinUI 3。 对于 WinUI 3 以外的框架,关系图的 XAML Window 框中显示的功能将由框架特定的恰当窗口 API 替换:

Window/AppWindow API 比较

如果使用 WinUI 3 XAML 作为应用的 UI 框架,那么 WindowAppWindow 两个 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 CreateGetFromWindowId
Activate 显示隐藏
CloseClosed 销毁销毁关闭
>>> IdOwnerWindowId

在 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
>>> SetIconSetTaskbarIconSetTitleBarIcon
ExtendsContentIntoTitleBar AppWindow.TitleBar.ExtendsContentIntoTitleBar

可以不同程度地修改应用的标题栏;设置标题和图标、更改颜色或完全将标题栏替换为自定义应用内容。

有关使用标题栏 API(包括代码示例)的信息,请参阅 标题栏自定义

大小和位置

XAML Window AppWindow
Bounds PositionSizeClientSize
SizeChanged 已更改DidPositionChangeDidSizeChange
>>> MoveResizeResizeClientMoveAndResize
>>> MoveInZOrderAtBottomMoveInZOrderAtTopMoveInZOrderBelow

您可以使用 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 DispatcherQueueAssociateWithDispatcherQueue
Compositor N/A

XAML Window API 通常负责应用内容的外观,例如背景。 有关 SystemBackdrop 的详细信息,请参阅 使用 Mica 或 Acrylic 材料

AppWindow API 负责窗口 的非客户端 部分以及应用与 Windows OS 的交互。

Note

XAML Window 类具有多个从 UWP Windows.UI.Xaml.Window 类继承的属性,但在 WinUI 应用中不支持。 这些属性始终具有值 null ,并且不在 WinUI 应用中使用: CoreWindowCurrentDispatcher

跟踪当前窗口

尽管 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。 有关详细信息和示例,请参阅 应用显示多个窗口