mirror of
https://github.com/AtomUI/AtomUI.git
synced 2026-10-29 07:16:33 +08:00
223 lines
12 KiB
Markdown
223 lines
12 KiB
Markdown
# Dialog 对话框
|
||
|
||
## 概述
|
||
|
||
对话框(Dialog)是一个从界面中弹出的模态或非模态面板,用于承载需要用户关注或交互的内容。典型使用场景包括:确认操作、表单填写、详情展示、流程引导等。对话框在出现时会在视觉上「聚焦」用户注意力,阻止(模态)或不阻止(非模态)用户与底层界面的交互。
|
||
|
||
AtomUI 的 `Dialog` 控件对应 Ant Design 的 [Modal 组件](https://ant.design/components/modal-cn)。在 AtomUI 中采用 `Dialog` 命名(而非 `Modal`),是因为 `Dialog` 更准确地描述了桌面端的语义——桌面应用中「对话框」是长期沿用的标准术语,且 AtomUI 的实现不仅支持模态(Modal),还支持非模态(Modeless)模式。
|
||
|
||
---
|
||
|
||
## 设计原理
|
||
|
||
### Ant Design 的对话框设计哲学
|
||
|
||
Ant Design 对 Modal 的定位是:**在当前页面打开一个浮层,承载相关操作或信息。用户不需要离开当前页面就能完成任务或获取信息**。
|
||
|
||
**典型使用场景:**
|
||
|
||
| 场景 | 说明 |
|
||
|---|---|
|
||
| 🔔 **信息确认** | 操作前的二次确认(如删除、提交),避免误操作 |
|
||
| 📝 **表单填写** | 在不离开当前页面的情况下完成新建/编辑等操作 |
|
||
| 📄 **详情展示** | 展示详细信息或预览内容 |
|
||
| ⚠️ **消息提示** | 成功、错误、警告、确认等快捷提示(MessageBox) |
|
||
|
||
### AtomUI 的扩展设计
|
||
|
||
AtomUI `Dialog` 在 Ant Design Modal 基础上做了大量桌面端增强,核心设计决策包括:
|
||
|
||
**双宿主架构(Dual Host):**
|
||
|
||
| 宿主类型 | 说明 | 适用场景 |
|
||
|---|---|---|
|
||
| `Overlay` | 基于 Overlay 层渲染,在当前窗口内覆盖显示 | 大多数场景(默认);对话框内容与主窗口共享渲染上下文 |
|
||
| `Window` | 创建独立的原生窗口作为宿主 | 需要独立标题栏、系统窗口管理器交互、最小化/最大化等 |
|
||
|
||
**标准按钮系统(Standard Buttons):**
|
||
|
||
Dialog 提供了一套完整的标准按钮系统,基于 `DialogStandardButton` 枚举(Flags),支持 `Ok`、`Cancel`、`Save`、`Yes`、`No`、`Apply`、`Reset` 等 18 种标准按钮。每个标准按钮都有预定义的 `DialogButtonRole`(AcceptRole / RejectRole / DestructiveRole 等),Dialog 根据角色自动决定点击后的行为(Accept / Reject / Done)。
|
||
|
||
**定位系统(Positioning):**
|
||
|
||
Dialog 提供了灵活的定位能力:
|
||
- `HorizontalStartupLocation` / `VerticalStartupLocation`:锚点定位(Left / Center / Right / Top / Bottom / Custom)
|
||
- `HorizontalOffset` / `VerticalOffset`:偏移量,支持像素和百分比(`Dimension` 类型)
|
||
- `PlacementTarget`:定位参考控件
|
||
- `PlacementCallback`:完全自定义定位回调
|
||
|
||
**MVVM 集成:**
|
||
|
||
通过 `IDialogAwareDataContext` 接口,ViewModel 可以感知自身被关联到哪个 Dialog 实例,从而在 ViewModel 层主动关闭对话框、获取结果等。
|
||
|
||
---
|
||
|
||
## 功能详解
|
||
|
||
### 宿主类型(DialogHostType)
|
||
|
||
通过 `DialogHostType` 属性选择宿主:
|
||
|
||
- **Overlay(默认)**:对话框渲染在当前窗口的 Overlay 层上,通过 `OverlayDialogHost` 实现。支持拖拽移动、调整大小、遮罩层。
|
||
- **Window**:对话框在独立的 `DialogHost`(继承自 `Window`)中渲染。支持系统窗口标题栏、最小化、最大化、原生拖拽。
|
||
|
||
### 模态与非模态
|
||
|
||
- **模态(IsModal = true,默认)**:打开后阻止用户与底层界面交互。`OpenAsync()` 返回的 Task 在对话框关闭后才完成,可以直接 `await` 获取 `Result`。
|
||
- **非模态(IsModal = false)**:打开后不阻止用户操作底层界面。`OpenAsync()` 在对话框显示后立即完成。
|
||
|
||
### 标准按钮与自定义按钮
|
||
|
||
- **标准按钮**:通过 `StandardButtons` 属性配置,例如 `StandardButtons="Ok, Cancel"`。
|
||
- **默认按钮**:通过 `DefaultStandardButton` 指定哪个标准按钮为默认确认按钮(视觉上高亮显示)。
|
||
- **自定义按钮**:通过 `CustomButtons` 集合添加 `DialogButton` 实例,可自定义文本、角色和样式。
|
||
- **按钮属性配置回调**:`ButtonsConfigure` 回调可在按钮创建后统一修改属性(如禁用所有按钮)。
|
||
|
||
### 加载状态
|
||
|
||
- **IsLoading**:整体加载状态,对话框内容区域显示加载遮罩。
|
||
- **IsConfirmLoading**:确认按钮加载状态。当 `IsConfirmLoading = true` 时,对话框不会响应关闭请求,防止用户在异步操作完成前关闭对话框。
|
||
|
||
### 拖拽与调整大小
|
||
|
||
- **IsDragMovable**:启用标题栏拖拽移动。
|
||
- **IsResizable**:启用对话框边缘拖拽调整大小。
|
||
- **IsMaximizable**:启用最大化按钮。
|
||
|
||
### 关闭流程
|
||
|
||
Dialog 提供三种关闭方式:
|
||
1. **Accept()**:设置 `Result = DialogCode.Accepted`,触发 `Accepted` 事件后关闭。
|
||
2. **Reject()**:设置 `Result = DialogCode.Rejected`,触发 `Rejected` 事件后关闭。
|
||
3. **Done(result?)**:设置自定义 Result 后关闭,触发 `Finished` 事件。
|
||
|
||
关闭前会触发 `Closing` 事件(`CancelEventArgs`),可以通过设置 `Cancel = true` 阻止关闭。当 `IsConfirmLoading = true` 时,所有关闭请求均被忽略。
|
||
|
||
**按钮角色到关闭行为的映射:**
|
||
|
||
当底部按钮被点击时,Dialog 首先触发 `ButtonClicked` 事件。若未被 `Handled`,则根据按钮角色自动执行:
|
||
|
||
| 按钮角色 | 关闭行为 |
|
||
|---|---|
|
||
| `AcceptRole` / `YesRole` / `ApplyRole` / `ResetRole` | 调用 `Accept()`(Result = Accepted) |
|
||
| `RejectRole` / `NoRole` | 调用 `Reject()`(Result = Rejected) |
|
||
| `ActionRole` / `HelpRole` / `CustomRole` / `DestructiveRole` | 不自动关闭,需在 `ButtonClicked` 事件中自行处理 |
|
||
|
||
### 静态 API
|
||
|
||
Dialog 提供了一组静态方法,用于在代码中快速创建和显示对话框,无需在 AXAML 中声明:
|
||
|
||
- `Dialog.ShowDialog(...)` / `Dialog.ShowDialogModal(...)` — 同步打开
|
||
- `Dialog.ShowDialogAsync(...)` / `Dialog.ShowDialogModalAsync(...)` — 异步打开
|
||
- 泛型版本 `Dialog.ShowDialogModalAsync<TView, TViewModel>(...)` — 用于自定义视图 + ViewModel
|
||
|
||
---
|
||
|
||
## 与 Ant Design 规范的对齐程度
|
||
|
||
| 特性 | Ant Design (React) | AtomUI (Avalonia) | 对齐情况 |
|
||
|---|---|---|---|
|
||
| 模态弹窗 | ✅ `Modal` | ✅ `Dialog` | ✅ 完全对齐(命名不同) |
|
||
| 标题 | ✅ `title` | ✅ `Title` 属性 | ✅ 完全对齐 |
|
||
| 内容 | ✅ `children` | ✅ `Content` 属性 | ✅ 完全对齐 |
|
||
| 页脚按钮 | ✅ `footer` / `okText` / `cancelText` | ✅ `StandardButtons` + `CustomButtons` | ✅ 增强:支持 18 种标准按钮 |
|
||
| 确认加载 | ✅ `confirmLoading` | ✅ `IsConfirmLoading` | ✅ 完全对齐 |
|
||
| 关闭按钮 | ✅ `closable` | ✅ `IsClosable` | ✅ 完全对齐 |
|
||
| 遮罩层 | ✅ `mask` | ✅ Overlay 模式自带遮罩 | ✅ 完全对齐 |
|
||
| 点击遮罩关闭 | ✅ `maskClosable` | ✅ `IsLightDismissEnabled` | ✅ 完全对齐 |
|
||
| 居中显示 | ✅ `centered` | ✅ `HorizontalStartupLocation="Center"` | ✅ 完全对齐(更灵活) |
|
||
| 宽度 | ✅ `width` | ✅ `Width` / `MinWidth` / `MaxWidth` | ✅ 完全对齐 |
|
||
| 加载中 | ✅ `loading` | ✅ `IsLoading` | ✅ 完全对齐 |
|
||
| 拖拽移动 | ❌ 不支持 | ✅ `IsDragMovable` | ⭐ AtomUI 增强 |
|
||
| 调整大小 | ❌ 不支持 | ✅ `IsResizable` | ⭐ AtomUI 增强 |
|
||
| 窗口宿主 | ❌ 不适用(Web) | ✅ `DialogHostType.Window` | ⭐ AtomUI 桌面端增强 |
|
||
| 最大化/最小化 | ❌ 不适用 | ✅ `IsMaximizable` / `IsMinimizable` | ⭐ AtomUI 桌面端增强 |
|
||
| 标准按钮系统 | ❌ 仅 Ok/Cancel | ✅ 18 种标准按钮 + 角色系统 | ⭐ AtomUI 增强 |
|
||
| MVVM 集成 | ❌ 不适用 | ✅ `IDialogAwareDataContext` | ⭐ AtomUI 增强 |
|
||
| `Modal.confirm()` | ✅ 静态方法 | ✅ `Dialog.ShowDialogModalAsync()` | ✅ 完全对齐 |
|
||
|
||
---
|
||
|
||
## 继承关系
|
||
|
||
```
|
||
Avalonia.Controls.Primitives.TemplatedControl
|
||
└── AtomUI.Desktop.Controls.Dialog
|
||
├── implements IDialogHostProvider
|
||
├── implements IMotionAwareControl
|
||
└── implements IDialog
|
||
```
|
||
|
||
`Dialog` 直接继承自 Avalonia 的 `TemplatedControl`,未使用 `ContentControl` 或 `Window`。内容通过 `Content` 属性传递给宿主(`OverlayDialogHost` 或 `DialogHost`)进行渲染。Dialog 本身不参与可视化树的测量和排列(`MeasureCore` 返回空尺寸),其唯一职责是管理对话框的生命周期和状态。
|
||
|
||
**各层级职责划分:**
|
||
|
||
| 层级 | 提供的能力 |
|
||
|---|---|
|
||
| `TemplatedControl` | 模板化控件基础设施 |
|
||
| `Dialog` | 对话框生命周期管理(打开/关闭/结果)、双宿主架构、标准按钮系统、定位系统、加载状态、拖拽/调整大小、MVVM 集成 |
|
||
|
||
**实现的接口:**
|
||
|
||
| 接口 | 定义位置 | 作用 |
|
||
|---|---|---|
|
||
| `IDialog` | `AtomUI.Desktop.Controls` | 对话框核心协议:Title、Result、生命周期事件、Accept/Reject/Done |
|
||
| `IDialogHostProvider` | `AtomUI.Desktop.Controls` | 提供对宿主(DialogHost)的访问 |
|
||
| `IMotionAwareControl` | `AtomUI.Controls.Shared` | 支持 `IsMotionEnabled` 动画开关 |
|
||
|
||
---
|
||
|
||
## 源码位置
|
||
|
||
| 层级 | 文件路径 | 说明 |
|
||
|---|---|---|
|
||
| 控件类 | `src/AtomUI.Desktop.Controls/Dialog/Dialog.cs` | Dialog 核心实现 |
|
||
| 静态 API | `src/AtomUI.Desktop.Controls/Dialog/Dialog.StaticAPI.cs` | 静态方法 |
|
||
| 配置选项 | `src/AtomUI.Desktop.Controls/Dialog/DialogOptions.cs` | 静态 API 的配置参数 |
|
||
| 接口 | `src/AtomUI.Desktop.Controls/Dialog/IDialog.cs` | IDialog 接口 |
|
||
| MVVM 接口 | `src/AtomUI.Desktop.Controls/Dialog/IDialogAwareDataContext.cs` | ViewModel 感知接口 |
|
||
| 宿主类型 | `src/AtomUI.Desktop.Controls/Dialog/DialogHostType.cs` | Overlay / Window 枚举 |
|
||
| 定位枚举 | `src/AtomUI.Desktop.Controls/Dialog/DialogPlacement.cs` | 水平/垂直锚点枚举 |
|
||
| 按钮系统 | `src/AtomUI.Desktop.Controls/Dialog/ButtonBox/` | DialogButton、DialogButtonRole、DialogStandardButton 等 |
|
||
| Token 定义 | `src/AtomUI.Desktop.Controls/Dialog/DialogToken.cs` | 组件级 Design Token |
|
||
| 主题 | `src/AtomUI.Desktop.Controls/Dialog/Themes/` | ControlTheme 及 code-behind |
|
||
| Gallery 示例 | `controlgallery/AtomUIGallery/ShowCases/Views/Feedback/ModalShowCase.axaml` | 使用范例 |
|
||
|
||
---
|
||
|
||
## 模板结构
|
||
|
||
Dialog 本身不直接渲染可视内容,而是将属性代理给宿主。根据 `DialogHostType` 的不同,使用不同的宿主模板:
|
||
|
||
### Overlay 宿主模板结构
|
||
|
||
```
|
||
OverlayDialogHost
|
||
├── OverlayDialogMask ← 遮罩层(模态时显示)
|
||
└── OverlayDialogResizer (PART_Resizer) ← 调整大小控件
|
||
└── StackPanel
|
||
├── OverlayDialogHeader (PART_Header) ← 标题栏(标题、图标、关闭/最大化按钮)
|
||
├── ContentPresenter ← 内容区域
|
||
└── DialogButtonBox (PART_ButtonBox) ← 底部按钮区域
|
||
```
|
||
|
||
### Window 宿主模板结构
|
||
|
||
```
|
||
DialogHost (extends Window)
|
||
├── 系统窗口标题栏 ← 原生标题栏(标题、最小化/最大化/关闭)
|
||
└── StackPanel
|
||
├── ContentPresenter ← 内容区域
|
||
└── DialogButtonBox (PART_ButtonBox) ← 底部按钮区域
|
||
```
|
||
|
||
### 模板部件常量
|
||
|
||
| 常量名 | 值 | 所属类 | 说明 |
|
||
|---|---|---|---|
|
||
| `OverlayDialogThemeConstants.ResizerPart` | `"PART_Resizer"` | OverlayDialogHost | 调整大小控件 |
|
||
| `OverlayDialogThemeConstants.HeaderPart` | `"PART_Header"` | OverlayDialogHost | 标题栏 |
|
||
| `OverlayDialogHeaderThemeConstants.CloseButtonPart` | `"PART_CloseButton"` | OverlayDialogHeader | 关闭按钮 |
|
||
| `OverlayDialogHeaderThemeConstants.MaximizeButtonPart` | `"PART_MaximizeButton"` | OverlayDialogHeader | 最大化按钮 |
|
||
| `DialogThemeConstants.ButtonBoxPart` | `"PART_ButtonBox"` | Dialog/DialogHost | 按钮区域 |
|