16 KiB
ComboBox 组合框
概述
组合框(ComboBox)是最基础的下拉选择控件,用户通过点击触发下拉面板,从预定义的选项列表中选择一个值。它广泛用于表单填写、筛选条件设置、配置项选择等场景——当候选项较多时,下拉选择比单选框更节省空间;当需要精确匹配时,下拉选择比自由输入更可靠。
AtomUI 的 ComboBox 控件对齐 Ant Design 5.0 Select (basic) 的基础模式设计规范,在 .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 向下箭头图标