15 KiB
Window 窗口
概述
Window 是 AtomUI 主题化的窗口控件,提供了自定义标题栏、多层框架(Frame Layer)背景、响应式媒体查询(Media Query)、操作系统感知、窗口拖拽与缩放等能力。它是桌面应用程序的顶层容器,所有 AtomUI 控件都运行在 Window 或其子类 ReactiveWindow<TViewModel> 之内。
这是 AtomUI 的扩展控件,在 Ant Design 中没有直接对应。其设计灵感部分来源于 SukiUI 项目。
设计原理
窗口控件的设计目标
桌面应用程序与 Web 应用最大的区别之一在于窗口管理。AtomUI 的 Window 控件旨在提供:
- 统一的主题化外观:窗口背景、前景色通过 Design Token 系统控制,自动适配亮色/暗色主题切换。
- 自定义标题栏:替代操作系统原生标题栏,提供可配置的 Logo、标题、标题按钮(关闭/最大化/最小化/全屏/置顶)。
- 多层框架背景:支持 Window 整体框架层、标题栏框架层、内容区框架层的独立背景设置,可用于实现渐变、图片背景等高级视觉效果。
- 响应式布局:内置媒体查询系统,基于窗口内容区域宽度自动计算断点,支持响应式 UI 布局。
- 跨平台适配:自动识别 Windows/macOS/Linux 平台,针对各平台进行标题栏、边框、装饰等差异化处理。
Avalonia Window 基础能力
AtomUI 的 Window 继承自 Avalonia 框架的 Avalonia.Controls.Window。理解 Avalonia Window 的基础能力有助于理解 AtomUI 在其之上做了哪些扩展。
Avalonia Window 的核心职责:
Avalonia 的 Window 是一个顶层容器控件(TopLevel),它负责管理操作系统级别的窗口生命周期、大小、位置、状态(最小化/最大化/全屏/正常)以及系统装饰(标题栏、边框)。其继承链为:
Control → TemplatedControl → ContentControl → TopLevel → WindowBase → Window
Avalonia Window 提供的基础属性:
| 属性 | 说明 |
|---|---|
Title |
窗口标题文本 |
Icon |
窗口图标 |
WindowState |
窗口状态:Normal、Minimized、Maximized、FullScreen |
WindowStartupLocation |
启动位置:Manual、CenterScreen、CenterOwner |
CanResize |
是否允许调整窗口大小 |
CanMinimize / CanMaximize |
是否允许最小化/最大化 |
SystemDecorations |
系统装饰风格:None、BorderOnly、Full |
ExtendClientAreaToDecorationsHint |
是否将客户区扩展到标题栏装饰区域 |
TransparencyLevelHint |
透明度级别提示 |
Content |
窗口内容 |
Topmost |
是否置顶显示 |
ShowInTaskbar |
是否在任务栏显示 |
AtomUI 的扩展设计
AtomUI Window 在 Avalonia Window 的基础上做了以下扩展:
| 扩展能力 | 实现方式 | 设计动机 |
|---|---|---|
| 自定义标题栏 | WindowTitleBar 控件 + IsTitleBarVisible 属性 |
替代原生标题栏,提供统一的跨平台外观和可配置性 |
| 多层框架背景 | WindowFrameLayer / ContentFrameLayer / TitleBarFrameLayer 属性 |
支持为窗口不同区域设置独立的背景内容,实现渐变/图片/动画背景 |
| 响应式媒体查询 | WindowMediaQueryIndicator + MediaBreakPoint + Container Query |
基于内容区域宽度自动计算断点,驱动响应式布局 |
| 操作系统感知 | IOperationSystemAware 接口 + OsType 属性 |
自动识别平台,针对不同 OS 应用差异化样式 |
| 窗口缩放控制 | WindowResizer 控件(Linux 专用) |
在 Linux 无系统装饰环境下提供自定义缩放手柄 |
| 屏幕比例限制 | MaxWidthScreenRatio / MaxHeightScreenRatio |
按屏幕工作区比例约束窗口最大尺寸 |
| 标题按钮配置 | IsFullScreenCaptionButtonEnabled / IsPinCaptionButtonEnabled / IsCloseCaptionButtonEnabled |
灵活控制标题栏功能按钮的显示/隐藏 |
| 窗口拖拽控制 | IsMoveEnabled 属性 |
可禁用标题栏拖拽移动功能 |
| macOS 原生集成 | MacOSCaptionGroupOffset / MacOSCaptionGroupSpacing |
精确控制 macOS 红绿灯按钮的位置和间距 |
| ReactiveUI 集成 | ReactiveWindow<TViewModel> 泛型子类 |
原生支持 MVVM 模式,ViewModel 自动激活 |
| Design Token | WindowToken + Token 资源系统 |
窗口背景/前景/圆角等视觉值从全局 Token 派生 |
| 全局对话框支持 | 模板内嵌 DialogLayerManager + GlobalDialogManager |
窗口级别的对话框/模态层管理 |
功能详解
自定义标题栏(WindowTitleBar)
Window 默认使用 WindowTitleBar 控件替代操作系统原生标题栏。标题栏通过 ExtendClientAreaToDecorationsHint = True 将客户区扩展到装饰区域,实现完全自定义的标题栏外观。
标题栏提供以下功能:
- Logo:通过
Window.Logo属性设置,通常为应用程序图标 - 标题文本:通过
Window.Title属性设置,字号和字重由TitleFontSize/TitleFontWeight控制 - 标题按钮组:关闭、最小化、最大化/还原、全屏、置顶按钮
- 双击最大化/还原:双击标题栏在 Normal 和 Maximized 之间切换
- 拖拽移动:鼠标在标题栏按住拖拽以移动窗口,超过
DragThreshold阈值后触发
标题栏可通过 IsTitleBarVisible = false 完全隐藏。
多层框架背景(Frame Layers)
Window 模板支持三个独立的背景层,每层可设置内容、模板和不透明度:
| 框架层 | 范围 | 属性 |
|---|---|---|
| WindowFrameLayer | 覆盖整个窗口区域(标题栏 + 内容区) | WindowFrameLayer / WindowFrameLayerTemplate / WindowFrameLayerOpacity |
| TitleBarFrameLayer | 仅覆盖标题栏区域 | TitleBarFrameLayer / TitleBarFrameLayerTemplate / TitleBarFrameLayerOpacity / TitleBarFrameBackground |
| ContentFrameLayer | 仅覆盖内容区域 | ContentFrameLayer / ContentFrameLayerTemplate / ContentFrameLayerOpacity / ContentFrameBackground |
通过这些框架层,可以实现渐变背景、图片背景、动画背景等丰富的视觉效果,而不影响窗口内容的正常渲染。
响应式媒体查询(Media Query)
Window 内置了响应式媒体查询系统,基于 Avalonia Container Query 机制实现。内容区域的 Border#ContentFrame 被标记为 Container Query 容器,WindowMediaQueryIndicator 根据容器宽度自动更新断点值:
| 断点名称 | 容器宽度范围 | 枚举值 |
|---|---|---|
ExtraSmall |
≤ 575px | MediaBreakPoint.ExtraSmall |
Small |
≥ 576px | MediaBreakPoint.Small |
Medium |
≥ 768px | MediaBreakPoint.Medium |
Large |
≥ 992px(默认) | MediaBreakPoint.Large |
ExtraLarge |
≥ 1200px | MediaBreakPoint.ExtraLarge |
ExtraExtraLarge |
≥ 1600px | MediaBreakPoint.ExtraExtraLarge |
断点变化时会更新 Window.MediaBreakPoint 属性并触发 MediaBreakPointChanged 事件,子控件可通过实现 IMediaBreakAwareControl 接口响应布局变化。
操作系统感知
Window 实现了 IOperationSystemAware 接口,在构造时自动检测当前操作系统并设置 OsType 属性。主题系统通过 [OsType=Windows]、[OsType=Linux]、[OsType=macOS] 属性选择器应用平台差异化样式:
| 平台 | 差异化行为 |
|---|---|
| Windows | ExtendClientAreaTitleBarHeightHint = 1,最大化时自动添加 7px Margin 避免边缘溢出 |
| Linux | SystemDecorations = None,ExtendClientAreaChromeHints = NoChrome,启用自定义 WindowResizer,窗口带 1px 边框和 12px 圆角 |
| macOS | 使用原生红绿灯按钮(通过 MacOSCaptionGroupOffset/MacOSCaptionGroupSpacing 定位),支持通过原生 API 控制关闭按钮可用性 |
窗口缩放器(WindowResizer)
WindowResizer 是一个仅在 Linux 平台可见的内部控件,提供 8 个方向的缩放手柄(N/S/E/W/NW/NE/SW/SE)。由于 Linux 下 SystemDecorations = None,没有系统提供的缩放边框,因此由 AtomUI 自行绘制透明的缩放区域。
ReactiveWindow<TViewModel>
ReactiveWindow<TViewModel> 是 Window 的 ReactiveUI 集成版本,实现了 IViewFor<TViewModel> 接口。它提供:
ViewModel属性与DataContext的自动双向同步- 如果 ViewModel 实现了
IActivatableViewModel,窗口显示时自动激活 ViewModel - 完整的
WhenActivated生命周期管理
继承关系
Avalonia.Controls.Primitives.TemplatedControl
└── Avalonia.Controls.ContentControl
└── Avalonia.Controls.TopLevel
└── Avalonia.Controls.WindowBase
└── Avalonia.Controls.Window
└── AtomUI.Desktop.Controls.Window
├── implements IOperationSystemAware
├── implements IMediaBreakAwareControl
├── implements IDisposable
│
└── AtomUI.Desktop.Controls.ReactiveWindow<TViewModel>
└── implements IViewFor<TViewModel>
Window 通过 using AvaloniaWindow = Avalonia.Controls.Window; 别名引用 Avalonia 原生 Window,避免类名冲突。
各层级职责划分:
| 层级 | 提供的能力 |
|---|---|
TopLevel / WindowBase |
顶层容器管理、平台实现桥接、渲染启动、DPI 缩放 |
Avalonia.Controls.Window |
窗口状态管理(Normal/Minimized/Maximized/FullScreen)、系统装饰、标题栏高度提示、透明度、启动位置、模态窗口、关闭逻辑 |
AtomUI.Desktop.Controls.Window |
自定义标题栏、多层框架背景、响应式媒体查询、操作系统感知、屏幕比例约束、标题按钮配置、Design Token 集成、全局对话框管理 |
ReactiveWindow<TViewModel> |
ReactiveUI MVVM 集成、ViewModel 自动激活、DataContext ↔ ViewModel 同步 |
实现的共享接口:
| 接口 | 定义位置 | 作用 |
|---|---|---|
IOperationSystemAware |
AtomUI.Controls.Shared |
自动检测并暴露当前操作系统类型和版本 |
IMediaBreakAwareControl |
AtomUI.Controls.Shared |
提供 MediaBreakPoint 属性和 MediaBreakPointChanged 事件,支持响应式布局 |
IDisposable |
System |
窗口关闭时清理事件订阅等资源 |
源码位置
| 层级 | 文件路径 | 说明 |
|---|---|---|
| 控件类 | src/AtomUI.Desktop.Controls/Window/Window.cs |
Window 主控件 |
| 控件类 | src/AtomUI.Desktop.Controls/Window/ReactiveWindow.cs |
ReactiveUI 集成的泛型窗口 |
| 扩展方法 | src/AtomUI.Desktop.Controls/Window/WindowExtensions.cs |
窗口辅助方法(屏幕居中、尺寸约束等) |
| 内部控件 | src/AtomUI.Desktop.Controls/Window/WindowMediaQueryIndicator.cs |
媒体查询断点指示器 |
| 内部控件 | src/AtomUI.Desktop.Controls/Window/WindowResizer.cs |
Linux 窗口缩放器 |
| 反射扩展 | src/AtomUI.Desktop.Controls/Window/WindowBaseReflectionExtensions.cs |
WindowBase 反射辅助(ShowWithoutActive 等) |
| 转换器 | src/AtomUI.Desktop.Controls/Window/Converters/WindowShadowsToPaddingConverter.cs |
BoxShadows → Thickness 转换 |
| Token 定义 | src/AtomUI.Desktop.Controls/Window/WindowToken.cs |
组件级 Design Token |
| 主题模板 | src/AtomUI.Desktop.Controls/Window/Themes/WindowTheme.axaml |
ControlTheme AXAML |
| 主题代码 | src/AtomUI.Desktop.Controls/Window/Themes/WindowTheme.cs |
主题 code-behind |
| 模板常量 | src/AtomUI.Desktop.Controls/Window/Themes/WindowThemeConstants.cs |
模板部件名称常量 |
| 缩放器主题 | src/AtomUI.Desktop.Controls/Window/Themes/WindowResizerTheme.axaml |
WindowResizer 主题 |
| 主题注册 | src/AtomUI.Desktop.Controls/Window/Themes/WindowThemes.axaml |
ResourceDictionary 注册 |
| 标题栏 | src/AtomUI.Desktop.Controls/Chrome/WindowTitleBar.cs |
标题栏控件 |
| 标题栏 Token | src/AtomUI.Desktop.Controls/Chrome/ChromeToken.cs |
标题栏/标题按钮 Design Token |
| Gallery 示例 | controlgallery/AtomUIGallery/Workspace/Views/WorkspaceWindow.axaml |
Gallery 主窗口使用范例 |
模板结构
Window 的 ControlTemplate 采用多层 Panel 布局,整体结构如下:
Panel
├── Border#WindowFrame ← 窗口主框架(承载背景、边框、圆角)
│ └── Panel
│ ├── ContentPresenter#WindowFrameLayer ← 窗口级框架背景层(可选,覆盖整个窗口)
│ └── Border (ClipToBounds)
│ └── DialogLayerManager ← 对话框/模态层管理器
│ └── Panel
│ ├── GlobalDialogManager ← 全局对话框管理器
│ └── DockPanel#PART_ContentLayout ← 内容布局容器
│ ├── Panel (Dock=Top, 标题栏区域)
│ │ ├── ContentPresenter#TitleBarFrameLayer ← 标题栏框架背景层
│ │ └── ContentPresenter (TitleBar) ← 标题栏控件
│ └── Panel (内容区域)
│ ├── ContentPresenter#ContentFrameLayer ← 内容区框架背景层
│ └── Border#ContentFrame ← 内容框架(Container Query 容器)
│ └── Panel
│ ├── ContentPresenter#PART_ContentPresenter ← 窗口内容展示
│ └── WindowMediaQueryIndicator#PART_MediaQueryIndicator ← 媒体查询指示器
└── WindowResizer#PART_WindowResizer ← 窗口缩放手柄(仅 Linux 可见)
分层设计理由:
- 框架背景层独立:
WindowFrameLayer、TitleBarFrameLayer、ContentFrameLayer作为独立的ContentPresenter层叠在内容之下,可放置图片、渐变等装饰内容而不影响交互。 - 对话框层嵌入:
DialogLayerManager包裹整个内容区域,确保对话框和模态遮罩可以覆盖标题栏和内容。 - 媒体查询容器:
Border#ContentFrame被标记为 Container Query 容器(Container.Name+Container.Sizing),WindowMediaQueryIndicator通过 Container Query 机制自动响应宽度变化。 - 缩放器叠加:
WindowResizer位于最顶层,覆盖窗口四边和四角,提供透明的缩放交互区域。
模板部件常量
| 常量名 | 值 | 说明 |
|---|---|---|
WindowThemeConstants.ContentPresenterPart |
"PART_ContentPresenter" |
内容展示器 |
WindowThemeConstants.WindowResizerPart |
"PART_WindowResizer" |
窗口缩放手柄 |
WindowThemeConstants.TitleBarPart |
"PART_TitleBar" |
标题栏控件 |
WindowThemeConstants.ContentLayoutPart |
"PART_ContentLayout" |
内容布局面板 |
WindowThemeConstants.MediaQueryIndicatorPart |
"PART_MediaQueryIndicator" |
媒体查询指示器 |