Files

16 KiB
Raw Permalink Blame History

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 向下箭头图标