mirror of
https://github.com/AtomUI/AtomUI.git
synced 2026-10-19 23:30:44 +08:00
241 lines
15 KiB
Markdown
241 lines
15 KiB
Markdown
# Window 窗口
|
||
|
||
## 概述
|
||
|
||
Window 是 AtomUI 主题化的窗口控件,提供了自定义标题栏、多层框架(Frame Layer)背景、响应式媒体查询(Media Query)、操作系统感知、窗口拖拽与缩放等能力。它是桌面应用程序的顶层容器,所有 AtomUI 控件都运行在 `Window` 或其子类 `ReactiveWindow<TViewModel>` 之内。
|
||
|
||
这是 AtomUI 的扩展控件,在 Ant Design 中没有直接对应。其设计灵感部分来源于 [SukiUI](https://github.com/kikipoulet/SukiUI) 项目。
|
||
|
||
---
|
||
|
||
## 设计原理
|
||
|
||
### 窗口控件的设计目标
|
||
|
||
桌面应用程序与 Web 应用最大的区别之一在于窗口管理。AtomUI 的 Window 控件旨在提供:
|
||
|
||
1. **统一的主题化外观**:窗口背景、前景色通过 Design Token 系统控制,自动适配亮色/暗色主题切换。
|
||
2. **自定义标题栏**:替代操作系统原生标题栏,提供可配置的 Logo、标题、标题按钮(关闭/最大化/最小化/全屏/置顶)。
|
||
3. **多层框架背景**:支持 Window 整体框架层、标题栏框架层、内容区框架层的独立背景设置,可用于实现渐变、图片背景等高级视觉效果。
|
||
4. **响应式布局**:内置媒体查询系统,基于窗口内容区域宽度自动计算断点,支持响应式 UI 布局。
|
||
5. **跨平台适配**:自动识别 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"` | 媒体查询指示器 |
|