mirror of
https://github.com/AtomUI/AtomUI.git
synced 2026-10-28 23:08:36 +08:00
275 lines
16 KiB
Markdown
275 lines
16 KiB
Markdown
# ComboBox 组合框
|
||
|
||
## 概述
|
||
|
||
组合框(ComboBox)是最基础的下拉选择控件,用户通过点击触发下拉面板,从预定义的选项列表中选择一个值。它广泛用于表单填写、筛选条件设置、配置项选择等场景——当候选项较多时,下拉选择比单选框更节省空间;当需要精确匹配时,下拉选择比自由输入更可靠。
|
||
|
||
AtomUI 的 `ComboBox` 控件对齐 [Ant Design 5.0 Select (basic)](https://ant.design/components/select-cn) 的基础模式设计规范,在 .NET / Avalonia 平台上提供与 Ant Design React 版一致的视觉体验和交互行为。
|
||
|
||
---
|
||
|
||
## 设计原理
|
||
|
||
### Ant Design 的 Select 设计哲学
|
||
|
||
Ant Design 的 Select 组件定位为:**「弹出一个下拉菜单给用户选择操作,用于代替原生的选择器」**。其核心设计理念包括:
|
||
|
||
**三种样式变体**(按视觉风格区分):
|
||
|
||
| 变体 | 设计意图 | 典型用途 |
|
||
|---|---|---|
|
||
| 🔲 **描边(Outlined)** | 默认样式,白色背景 + 实线边框,中等视觉权重 | 表单中的标准选择器 |
|
||
| 🟫 **填充(Filled)** | 灰色填充背景,无明显边框,较低视觉干扰 | 搜索栏、筛选器等辅助场景 |
|
||
| ➖ **无边框(Borderless)** | 无背景无边框,最轻量的视觉呈现 | 表格内嵌、只读展示等场景 |
|
||
|
||
**两种状态修饰**(用于表单验证反馈):
|
||
|
||
| 状态 | 设计意图 |
|
||
|---|---|
|
||
| ❌ **错误(Error)** | 红色系边框/底线,提示用户当前选择不满足验证规则 |
|
||
| ⚠️ **警告(Warning)** | 橙色系边框/底线,提示用户注意但不阻止提交 |
|
||
|
||
**AddOn 扩展区域**(前后附加内容):
|
||
|
||
| 区域 | 设计意图 |
|
||
|---|---|
|
||
| 🏷️ **前置标签(LeftAddOn)** | 选择器左侧外部附加区域,常用于协议前缀(如 `http://`) |
|
||
| 🏷️ **后置标签(RightAddOn)** | 选择器右侧外部附加区域,常用于域名后缀(如 `.com`) |
|
||
| 🔤 **内部前缀(ContentLeftAddOn)** | 内容区域左侧,常用于图标或货币符号 |
|
||
| 🔤 **内部后缀(ContentRightAddOn)** | 内容区域右侧,常用于单位或辅助图标 |
|
||
|
||
### Avalonia ComboBox 基础能力
|
||
|
||
AtomUI 的 `ComboBox` 继承自 Avalonia 框架的 `Avalonia.Controls.ComboBox`。理解 Avalonia ComboBox 的基础能力有助于理解 AtomUI 在其之上做了哪些扩展。
|
||
|
||
**Avalonia ComboBox 的核心职责:**
|
||
|
||
Avalonia 的 `ComboBox` 是一个标准的 `SelectingItemsControl`(选择型项目控件),它管理一组选项并允许用户从中选择一个。其继承链为:
|
||
|
||
```
|
||
Control → TemplatedControl → ItemsControl → SelectingItemsControl → ComboBox
|
||
```
|
||
|
||
作为 `SelectingItemsControl`,ComboBox 提供了完整的选择管理(`SelectedItem`、`SelectedIndex`、`SelectionChanged` 事件)、项目容器化(`ComboBoxItem`)、数据绑定(`ItemsSource` + `ItemTemplate`)、以及 `Popup` 弹出面板等基础设施。
|
||
|
||
**Avalonia ComboBox 提供的基础属性:**
|
||
|
||
| 属性 | 说明 |
|
||
|---|---|
|
||
| `ItemsSource` | 数据源集合,支持绑定任意 `IEnumerable` |
|
||
| `ItemTemplate` | 项目数据模板,定义每个选项的呈现方式 |
|
||
| `SelectedItem` | 当前选中项,支持双向绑定 |
|
||
| `SelectedIndex` | 当前选中项索引 |
|
||
| `PlaceholderText` | 未选中时显示的占位提示文本 |
|
||
| `IsDropDownOpen` | 下拉面板是否打开 |
|
||
| `MaxDropDownHeight` | 下拉面板最大高度 |
|
||
| `ItemsPanel` | 项目面板模板(默认为 `VirtualizingStackPanel`) |
|
||
|
||
**Avalonia ComboBox 提供的基础伪类:**
|
||
|
||
| 伪类 | 说明 |
|
||
|---|---|
|
||
| `:pointerover` | 鼠标悬浮在控件上 |
|
||
| `:pressed` | 控件被按下 |
|
||
| `:disabled` | `IsEnabled == false` |
|
||
| `:focus` | 控件获得焦点 |
|
||
| `:focus-visible` | 通过键盘(Tab)获得焦点 |
|
||
|
||
### AtomUI 的扩展设计
|
||
|
||
AtomUI `ComboBox` 在 Avalonia ComboBox 的基础上,遵循 Ant Design 5.0 规范做了以下扩展:
|
||
|
||
| 扩展能力 | 实现方式 | 设计动机 |
|
||
|---|---|---|
|
||
| **三种样式变体** | `InputControlStyleVariant` 枚举 + `AddOnDecoratedBox` 委托样式 | 对齐 Ant Design 的 `variant`,支持 Outlined / Filled / Borderless |
|
||
| **三种尺寸** | `ISizeTypeAware` 接口 + `SizeType` 共享属性 | 全局统一的 Large / Middle / Small 尺寸系统 |
|
||
| **验证状态** | `IInputControlStatusAware` 接口 + `Status` 属性 | 对齐 Ant Design 的 `status`,支持 Error / Warning 视觉反馈 |
|
||
| **AddOn 扩展区域** | `AddOnDecoratedBox` 装饰容器 + 8 个 AddOn 属性 | 复刻 Ant Design 的 addonBefore / addonAfter / prefix / suffix |
|
||
| **下拉手柄** | `ComboBoxHandle` 内置组件 + `IconButton` | 独立的下拉箭头按钮,带悬浮/按下颜色反馈 |
|
||
| **分页下拉高度** | `DropDownDisplayPageSize` 属性 + 自动计算 `MaxDropDownHeight` | 按项目数量控制下拉面板可见行数 |
|
||
| **过渡动画** | `IsMotionEnabled` + `Popup` 动画 | 下拉面板展开/收起的平滑过渡动画 |
|
||
| **表单集成** | `IFormItemAware` + `IFormItemFeedbackAware` 接口 | 可参与 FormItem 验证流程,自动显示反馈图标 |
|
||
| **Design Token** | `ComboBoxToken` + `RegisterTokenResourceScope` | 所有视觉值从全局/组件级 Token 派生,支持主题切换 |
|
||
|
||
---
|
||
|
||
## 功能详解
|
||
|
||
### 样式变体(StyleVariant)
|
||
|
||
样式变体通过 `StyleVariant` 属性设置,ComboBox 将该属性传递给内部的 `AddOnDecoratedBox` 容器,由后者统一管理边框/背景样式。三种变体的视觉差异:
|
||
|
||
| 变体 | 正常态 | 聚焦态 | 错误态 |
|
||
|---|---|---|---|
|
||
| `Outlined` | 白色背景 + 灰色边框 | 主色边框 + 外发光 | 红色边框 + 红色外发光 |
|
||
| `Filled` | 灰色填充背景 | 白色背景 + 主色边框 | 红色填充背景 + 红色边框 |
|
||
| `Borderless` | 无背景无边框 | 无边框 | 文本变为红色 |
|
||
|
||
### AddOn 扩展区域
|
||
|
||
ComboBox 支持四种扩展区域,均通过 `AddOnDecoratedBox` 实现:
|
||
|
||
| 区域 | 属性 | 位置 | 说明 |
|
||
|---|---|---|---|
|
||
| 前置标签 | `LeftAddOn` / `LeftAddOnTemplate` | 输入框外部左侧 | 带独立背景,常用于 `http://` 等前缀 |
|
||
| 后置标签 | `RightAddOn` / `RightAddOnTemplate` | 输入框外部右侧 | 带独立背景,常用于 `.com` 等后缀 |
|
||
| 内部前缀 | `ContentLeftAddOn` / `ContentLeftAddOnTemplate` | 内容区域左侧 | 与选中文本同行,常用于图标 |
|
||
| 内部后缀 | `ContentRightAddOn` / `ContentRightAddOnTemplate` | 内容区域右侧(手柄左侧) | 与选中文本同行,常用于辅助信息 |
|
||
|
||
### 下拉手柄(ComboBoxHandle)
|
||
|
||
ComboBox 内置一个 `ComboBoxHandle` 组件作为右侧内容附加件。手柄包含一个 `IconButton`(默认显示 `DownOutlined` 箭头图标),点击手柄可切换下拉面板的打开/关闭状态。手柄支持悬浮和按下时的颜色反馈。
|
||
|
||
### 下拉面板分页
|
||
|
||
`DropDownDisplayPageSize` 属性控制下拉面板最多可见的选项数量(默认 10 项)。AtomUI 会根据 `DropDownDisplayPageSize × ItemHeight + PopupContentPadding` 自动计算 `MaxDropDownHeight`,超出部分通过滚动条浏览。
|
||
|
||
### 验证状态(Status)
|
||
|
||
通过 `Status` 属性设置验证状态,对应的伪类(`:error`、`:warning`)会被激活。不同样式变体下的表现:
|
||
|
||
- **Outlined / Filled**:边框/背景颜色变为对应的错误/警告色系
|
||
- **Borderless**:选中文本的前景色变为对应的错误/警告色
|
||
|
||
### 表单集成
|
||
|
||
ComboBox 实现了 `IFormItemAware` 和 `IFormItemFeedbackAware` 接口:
|
||
- 当放置在 `FormItem` 中时,表单验证状态会自动映射为 `Status` 属性
|
||
- 验证反馈图标通过 `FormFeedback` 属性注入,显示在手柄左侧
|
||
|
||
---
|
||
|
||
## 与 Ant Design 规范的对齐程度
|
||
|
||
| 特性 | Ant Design (React) | AtomUI (Avalonia) | 对齐情况 |
|
||
|---|---|---|---|
|
||
| 三种变体 `variant` | ✅ `outlined / filled / borderless` | ✅ `StyleVariant` 枚举 | ✅ 完全对齐 |
|
||
| 三种尺寸 `size` | ✅ `large / medium / small` | ✅ `SizeType` 属性 | ✅ 完全对齐 |
|
||
| 验证状态 `status` | ✅ `error / warning` | ✅ `Status` 属性 | ✅ 完全对齐 |
|
||
| 占位文本 `placeholder` | ✅ 字符串 | ✅ `PlaceholderText` 属性 | ✅ 完全对齐 |
|
||
| 前后附加 `addonBefore / addonAfter` | ✅ ReactNode | ✅ `LeftAddOn` / `RightAddOn` | ✅ 完全对齐 |
|
||
| 前后缀 `prefix / suffix` | ✅ ReactNode | ✅ `ContentLeftAddOn` / `ContentRightAddOn` | ✅ 完全对齐 |
|
||
| 允许清除 `allowClear` | ✅ 布尔 | ✅ `IsAllowClear` 属性 | ✅ 完全对齐 |
|
||
| 禁用 `disabled` | ✅ 布尔 | ✅ `IsEnabled` 属性 | ✅ 完全对齐 |
|
||
| 搜索 `showSearch` | ✅ 搜索过滤 | ❌ 暂未支持 | ⚠️ 待支持 |
|
||
| 多选 `mode="multiple"` | ✅ 多选/标签 | ❌ 暂未支持 | ⚠️ 待支持 |
|
||
| 分组 `optionGroup` | ✅ 选项分组 | ❌ 暂未支持 | ⚠️ 待支持 |
|
||
| 虚拟滚动 `virtual` | ✅ 默认开启 | ⚠️ 通过 Avalonia VirtualizingStackPanel 部分支持 | ⚠️ 部分对齐 |
|
||
| 下拉面板自定义 `dropdownRender` | ✅ 自定义渲染 | ❌ 暂未支持 | ⚠️ 待支持 |
|
||
| 远程搜索 | ✅ 异步加载 | ❌ 暂未支持 | ⚠️ 待支持 |
|
||
|
||
---
|
||
|
||
## 继承关系
|
||
|
||
```
|
||
Avalonia.Controls.Primitives.TemplatedControl
|
||
└── Avalonia.Controls.ItemsControl
|
||
└── Avalonia.Controls.SelectingItemsControl
|
||
└── Avalonia.Controls.ComboBox
|
||
└── AtomUI.Desktop.Controls.ComboBox
|
||
├── implements IMotionAwareControl
|
||
├── implements ISizeTypeAware
|
||
├── implements IInputControlStatusAware
|
||
├── implements IInputControlStyleVariantAware
|
||
├── implements IFormItemAware
|
||
└── implements IFormItemFeedbackAware
|
||
```
|
||
|
||
`ComboBox` 通过 `using AvaloniaComboBox = Avalonia.Controls.ComboBox;` 别名引用 Avalonia 原生 ComboBox,避免类名冲突。
|
||
|
||
> **注意**:ComboBox 没有对应的 `Abstract*` 基类(在 `AtomUI.Controls` 层没有抽象基类),这是因为 ComboBox 直接继承自 Avalonia 的 `ComboBox`,扩展逻辑完全在 `AtomUI.Desktop.Controls` 层实现。
|
||
|
||
**各层级职责划分:**
|
||
|
||
| 层级 | 提供的能力 |
|
||
|---|---|
|
||
| `ItemsControl` | 项目集合管理、`ItemsSource` 数据绑定、`ItemTemplate` 模板化、容器回收 |
|
||
| `SelectingItemsControl` | 单选管理、`SelectedItem` / `SelectedIndex`、`SelectionChanged` 事件 |
|
||
| `Avalonia.Controls.ComboBox` | 下拉弹出 `Popup`、`PlaceholderText` 占位提示、`MaxDropDownHeight`、`IsDropDownOpen`、键盘导航、`SelectionBoxItem` 显示选中内容 |
|
||
| `AtomUI.Desktop.Controls.ComboBox` | Ant Design 视觉体系(三种变体/三种尺寸/验证状态)、AddOn 扩展区域、Design Token 集成、下拉手柄、分页下拉高度、表单集成 |
|
||
|
||
**实现的共享接口:**
|
||
|
||
| 接口 | 定义位置 | 作用 |
|
||
|---|---|---|
|
||
| `IMotionAwareControl` | `AtomUI.Controls.Shared` | 支持 `IsMotionEnabled` 动画开关 |
|
||
| `ISizeTypeAware` | `AtomUI.Controls.Shared` | 支持 `SizeType`(Small / Middle / Large)三种尺寸切换 |
|
||
| `IInputControlStatusAware` | `AtomUI.Controls.Shared` | 支持 `Status`(Error / Warning / Default)验证状态 |
|
||
| `IInputControlStyleVariantAware` | `AtomUI.Controls.Shared` | 支持 `StyleVariant`(Outlined / Filled / Borderless)样式变体 |
|
||
| `IFormItemAware` | `AtomUI.Controls.Shared` | 可作为 `FormItem` 的子控件参与表单验证 |
|
||
| `IFormItemFeedbackAware` | `AtomUI.Controls.Shared` | 可接收并显示表单验证反馈控件 |
|
||
|
||
---
|
||
|
||
## 源码位置
|
||
|
||
| 层级 | 文件路径 | 说明 |
|
||
|---|---|---|
|
||
| 控件类 | `src/AtomUI.Desktop.Controls/ComboBox/ComboBox.cs` | 桌面端 ComboBox 具体实现 |
|
||
| 控件类 | `src/AtomUI.Desktop.Controls/ComboBox/ComboBoxHandle.cs` | 下拉手柄组件(内部) |
|
||
| 控件类 | `src/AtomUI.Desktop.Controls/ComboBox/ComboBoxItem.cs` | 下拉选项容器 |
|
||
| 反射扩展 | `src/AtomUI.Desktop.Controls/ComboBox/ComboBoxReflectionExtensions.cs` | Avalonia ComboBox 内部字段访问 |
|
||
| Token 定义 | `src/AtomUI.Desktop.Controls/ComboBox/ComboBoxToken.cs` | 组件级 Design Token |
|
||
| 主题模板 | `src/AtomUI.Desktop.Controls/ComboBox/Themes/ComboBoxTheme.axaml` | ComboBox ControlTheme |
|
||
| 选项主题 | `src/AtomUI.Desktop.Controls/ComboBox/Themes/ComboBoxItemTheme.axaml` | ComboBoxItem ControlTheme |
|
||
| 手柄主题 | `src/AtomUI.Desktop.Controls/ComboBox/Themes/ComboBoxHandleTheme.axaml` | ComboBoxHandle ControlTheme |
|
||
| 主题注册 | `src/AtomUI.Desktop.Controls/ComboBox/Themes/ComboBoxThemes.axaml` | ResourceDictionary 聚合注册 |
|
||
| 模板常量 | `src/AtomUI.Desktop.Controls/ComboBox/Themes/ComboBoxThemeConstants.cs` | 模板部件名称常量 |
|
||
| Gallery 示例 | `controlgallery/AtomUIGallery/ShowCases/Views/Navigation/ComboBoxShowCase.axaml` | 使用范例 |
|
||
|
||
---
|
||
|
||
## 模板结构
|
||
|
||
ComboBox 的 ControlTemplate 采用 Panel 布局,分为两个主要区域:**AddOn 装饰容器**和**弹出下拉面板**。
|
||
|
||
```
|
||
Panel
|
||
├── AddOnDecoratedBox (PART_AddOnDecoratedBox) ← 装饰容器(管理边框/背景/AddOn 区域)
|
||
│ ├── [LeftAddOn] ← 前置标签(外部左侧)
|
||
│ ├── [ContentLeftAddOn] ← 内部前缀(内容左侧)
|
||
│ ├── Panel ← 内容区域
|
||
│ │ ├── TextBlock#PlaceholderText ← 占位提示文本(未选中时显示)
|
||
│ │ └── ContentPresenter#SelectedContentPresenter ← 选中内容展示器
|
||
│ ├── StackPanel (ContentRightAddOn) ← 内部后缀区域
|
||
│ │ ├── ContentPresenter (ContentRightAddOn) ← 用户自定义后缀
|
||
│ │ ├── ContentPresenter#FormFeedBack ← 表单验证反馈图标
|
||
│ │ └── ComboBoxHandle ← 下拉箭头手柄
|
||
│ └── [RightAddOn] ← 后置标签(外部右侧)
|
||
└── Popup (PART_Popup) ← 弹出下拉面板
|
||
└── Border#PopupFrame ← 弹出框架(背景/圆角/阴影)
|
||
└── ScrollViewer ← 滚动容器
|
||
└── ItemsPresenter (PART_ItemsPresenter) ← 选项列表
|
||
```
|
||
|
||
**分层设计理由:**
|
||
- **AddOnDecoratedBox 统一管理**:所有输入型控件(TextBox、ComboBox、ButtonSpinner 等)共用 `AddOnDecoratedBox` 作为外层装饰,确保样式变体(Outlined/Filled/Borderless)、验证状态、AddOn 区域的一致表现。
|
||
- **Popup 独立**:弹出面板使用 `atom:Popup`(AtomUI 增强版),支持动画展开/收起(`IsMotionAwareOpen`)和自动阴影。
|
||
- **手柄内置**:`ComboBoxHandle` 作为固定的内部后缀元素,始终显示在最右侧,确保下拉箭头的交互一致性。
|
||
|
||
### 模板部件常量
|
||
|
||
| 常量名 | 值 | 说明 |
|
||
|---|---|---|
|
||
| `ComboBoxThemeConstants.PopupPart` | `"PART_Popup"` | 弹出下拉面板 |
|
||
| `ComboBoxThemeConstants.SpinnerInnerBoxPart` | `"PART_SpinnerInnerBox"` | 内部输入框(预留) |
|
||
| `ComboBoxThemeConstants.ItemsPresenterPart` | `"PART_ItemsPresenter"` | 选项列表展示器 |
|
||
| `ComboBoxHandleThemeConstants.OpenIndicatorButtonPart` | `"PART_OpenIndicatorButton"` | 下拉指示器按钮 |
|
||
|
||
### ComboBoxItem 模板结构
|
||
|
||
```
|
||
ContentPresenter#ContentPresenter ← 选项内容展示器
|
||
Content → StringToTextBlockConverter ← 字符串自动转 TextBlock
|
||
Background / Padding / CornerRadius ← 由 Token 控制
|
||
Margin ← 由 ComboBoxToken.ItemMargin 控制
|
||
```
|
||
|
||
### ComboBoxHandle 模板结构
|
||
|
||
```
|
||
IconButton (PART_OpenIndicatorButton) ← 下拉指示器按钮
|
||
Icon = DownOutlined ← Ant Design 向下箭头图标
|
||
```
|