mirror of
https://github.com/AtomUI/AtomUI.git
synced 2026-10-20 15:52:17 +08:00
276 lines
15 KiB
Markdown
276 lines
15 KiB
Markdown
# AutoComplete 自动补全
|
||
|
||
## 概述
|
||
|
||
自动补全(AutoComplete)是输入型控件的增强组件,在用户键入文本时根据已有或动态获取的候选数据,实时展示匹配建议的下拉列表,用户可从中选取以快速完成输入。它广泛应用于搜索框联想、标签输入、邮箱/地址自动填充等需要"边输入边提示"的场景。
|
||
|
||
AtomUI 的 `AutoComplete` 控件对齐了 [Ant Design 5.0 AutoComplete](https://ant.design/components/auto-complete-cn) 的设计规范,在 .NET / Avalonia 平台上提供与 Ant Design React 版一致的视觉体验和交互行为,并在此基础上提供了异步数据加载、SearchEdit 集成、TextArea 集成等桌面端增强能力。
|
||
|
||
---
|
||
|
||
## 设计原理
|
||
|
||
### Ant Design 的自动补全设计哲学
|
||
|
||
Ant Design 对自动补全的定位是:**「输入框的自动补全功能,根据输入内容提供对应的输入建议」**。它与 Select 组件的本质区别在于:
|
||
|
||
- **AutoComplete** 是一个带辅助提示的**输入框**,用户的最终值是自由文本,候选只是建议。
|
||
- **Select** 是一个**选择器**,用户必须从预定义选项中选取。
|
||
|
||
Ant Design 的 AutoComplete 核心理念:
|
||
1. **实时过滤**:随着用户输入,候选列表实时筛选匹配项
|
||
2. **自定义渲染**:候选项可以自定义展示内容(不仅限于纯文本)
|
||
3. **灵活组合**:可与 Input、TextArea、Search 等输入组件组合使用
|
||
4. **异步加载**:支持远程搜索场景,根据输入内容动态请求候选数据
|
||
|
||
### Avalonia 基础能力
|
||
|
||
AtomUI 的 `AbstractAutoComplete` 直接继承自 Avalonia 的 `TemplatedControl`,而非 Avalonia 内置的 `AutoCompleteBox`。这是因为 AtomUI 需要:
|
||
|
||
1. 更深度地控制弹出层行为(使用 AtomUI 自定义的 `Popup` 和 `CandidateList`)
|
||
2. 集成 Design Token 系统和动画系统
|
||
3. 支持多种内嵌输入框类型(LineEdit、SearchEdit、TextArea)
|
||
4. 与 AtomUI 的 Form 验证体系、CompactSpace 等系统深度集成
|
||
|
||
继承链为:
|
||
|
||
```
|
||
TemplatedControl
|
||
└── AbstractAutoComplete (核心逻辑)
|
||
└── CompactSpaceAwareAutoComplete (紧凑空间适配)
|
||
└── AutoComplete (标准自动补全)
|
||
└── AutoCompleteSearchEdit (搜索型自动补全)
|
||
└── AutoCompleteTextArea (多行文本自动补全)
|
||
```
|
||
|
||
### AtomUI 的扩展设计
|
||
|
||
AtomUI AutoComplete 在基础输入能力之上做了以下扩展:
|
||
|
||
| 扩展能力 | 实现方式 | 设计动机 |
|
||
|---|---|---|
|
||
| **三种输入形态** | `AutoComplete` / `AutoCompleteSearchEdit` / `AutoCompleteTextArea` | 覆盖单行输入、搜索输入、多行输入三种典型场景 |
|
||
| **四种样式变体** | `StyleVariant` 枚举(Outline / Filled / Borderless / Underlined) | 对齐 Ant Design 5.0 的 `variant` 属性 |
|
||
| **三种尺寸** | `ISizeTypeAware` 接口 + `SizeType` 共享属性 | 全局统一的 Large / Middle / Small 尺寸系统 |
|
||
| **验证状态** | `IInputControlStatusAware` 接口 + `Status` 属性 | Error / Warning 状态视觉反馈 |
|
||
| **异步数据加载** | `ICompleteOptionsAsyncLoader` 接口 + `OptionsAsyncLoader` 属性 | 支持远程搜索、API 查询等异步场景 |
|
||
| **本地过滤** | `IValueFilter` 接口 + `Filter` 属性 | 内置 StartsWith / Contains 等多种过滤模式 |
|
||
| **自定义选项模板** | `OptionTemplate`(`IDataTemplate`) | 支持自定义候选项渲染(图标+文字、多列信息等) |
|
||
| **弹出方向控制** | `Placement` 属性(Top / Bottom) | 候选列表可在输入框上方或下方弹出 |
|
||
| **清除按钮** | `IsAllowClear` + `ClearIcon` | 一键清空输入内容 |
|
||
| **附加内容** | `ContentLeftAddOn` / `ContentRightAddOn` | 输入框前后附加图标或自定义内容 |
|
||
| **过渡动画** | `IsMotionEnabled` + Popup 动画 | 弹出/关闭候选列表的平滑过渡 |
|
||
| **紧凑空间** | `ICompactSpaceAware` 接口 | 在 `Space.Compact` 容器中自动调整圆角和边框 |
|
||
| **表单集成** | `IFormItemAware` + `IFormItemFeedbackAware` 接口 | 可参与 FormItem 验证流程 |
|
||
| **Design Token** | `AutoCompleteToken` + `RegisterTokenResourceScope` | 所有视觉值从全局/组件级 Token 派生 |
|
||
|
||
---
|
||
|
||
## 功能详解
|
||
|
||
### 三种输入形态
|
||
|
||
AutoComplete 家族包含三种控件,分别适用于不同的输入场景:
|
||
|
||
| 控件 | 内嵌输入框 | 适用场景 |
|
||
|---|---|---|
|
||
| `AutoComplete` | `LineEdit`(单行输入框) | 最常见的搜索联想、地址补全、标签输入等 |
|
||
| `AutoCompleteSearchEdit` | `SearchEdit`(搜索输入框) | 带搜索按钮的搜索联想场景 |
|
||
| `AutoCompleteTextArea` | `TextArea`(多行文本框) | 代码编辑器、评论框中的 @提及 等多行输入联想 |
|
||
|
||
三者共享 `AbstractAutoComplete` 中定义的全部核心逻辑(候选列表管理、过滤、弹出/关闭、键盘导航等),仅在内嵌输入框类型上有差异。
|
||
|
||
### 数据源与候选列表
|
||
|
||
AutoComplete 支持两种数据提供方式:
|
||
|
||
**1. 静态数据源(`OptionsSource`)**
|
||
|
||
直接设置 `IEnumerable<IAutoCompleteOption>` 集合:
|
||
|
||
```csharp
|
||
autoComplete.OptionsSource = new List<IAutoCompleteOption>
|
||
{
|
||
new AutoCompleteOption { Header = "选项一", Content = "选项一" },
|
||
new AutoCompleteOption { Header = "选项二", Content = "选项二" },
|
||
};
|
||
```
|
||
|
||
**2. 异步数据加载(`OptionsAsyncLoader`)**
|
||
|
||
实现 `ICompleteOptionsAsyncLoader` 接口,根据用户输入动态加载候选数据:
|
||
|
||
```csharp
|
||
public class MyLoader : ICompleteOptionsAsyncLoader
|
||
{
|
||
public async Task<CompleteOptionsLoadResult> LoadAsync(string? context, CancellationToken token)
|
||
{
|
||
var results = await MyApi.SearchAsync(context, token);
|
||
return new CompleteOptionsLoadResult { Data = results };
|
||
}
|
||
}
|
||
```
|
||
|
||
当设置了 `OptionsAsyncLoader` 时,每次用户输入满足 `MinimumPrefixLength` 条件后,自动调用加载器获取候选数据。
|
||
|
||
### 过滤机制
|
||
|
||
AutoComplete 提供灵活的过滤能力:
|
||
|
||
- **默认过滤**:`StartsWith`(前缀匹配,不区分大小写)
|
||
- **内置过滤模式**:通过 `{atom:ValueFilterProvider xxx}` 标记扩展在 AXAML 中直接使用
|
||
- `StartsWith` / `StartsWithCaseSensitive` / `StartsWithOrdinal` / `StartsWithOrdinalCaseSensitive`
|
||
- `Contains` / `ContainsCaseSensitive` / `ContainsOrdinal` / `ContainsOrdinalCaseSensitive`
|
||
- `Equals` / `EqualsCaseSensitive` / `EqualsOrdinal` / `EqualsOrdinalCaseSensitive`
|
||
- **自定义过滤**:实现 `IValueFilter` 接口
|
||
- **自定义取值**:通过 `FilterValueSelector` 委托控制从 `IAutoCompleteOption` 中取哪个字段做匹配
|
||
|
||
### 弹出候选列表
|
||
|
||
- 用户输入满足 `MinimumPrefixLength`(默认 1 个字符)后自动弹出
|
||
- 可通过 `MinimumPopulateDelay` 设置防抖延迟
|
||
- 支持 `DisplayCandidateCount` 控制最大可见候选项数量(默认 10)
|
||
- `MaxDropDownHeight` 直接控制弹出层最大高度
|
||
- `Placement` 控制弹出方向(`Top` / `Bottom`,默认 `Bottom`)
|
||
- `IsPopupMatchSelectWidth` 控制弹出层是否与输入框等宽(默认 `true`)
|
||
|
||
### 文本自动完成(IsCompletionEnabled)
|
||
|
||
当 `IsCompletionEnabled = true` 时,输入过程中会自动将最佳匹配项的文本填充到输入框,未输入部分自动选中,用户可继续输入覆盖或按 Enter 确认。
|
||
|
||
### 键盘导航
|
||
|
||
| 按键 | 行为 |
|
||
|---|---|
|
||
| `↓` | 下拉列表关闭时:打开。打开时:移动到下一候选项 |
|
||
| `↑` | 移动到上一候选项 |
|
||
| `Enter` | 确认当前选中的候选项 |
|
||
| `Escape` | 关闭候选列表,恢复输入值 |
|
||
| `F4` | 切换候选列表的打开/关闭状态 |
|
||
|
||
---
|
||
|
||
## 与 Ant Design 规范的对齐程度
|
||
|
||
| 特性 | Ant Design (React) | AtomUI (Avalonia) | 对齐情况 |
|
||
|---|---|---|---|
|
||
| 基本自动补全 | ✅ | ✅ `AutoComplete` | ✅ 完全对齐 |
|
||
| 自定义选项 `options` | ✅ | ✅ `OptionsSource` / `Options` | ✅ 完全对齐 |
|
||
| 自定义选项渲染 | ✅ `optionRender` | ✅ `OptionTemplate` | ✅ 对齐(机制不同,效果一致) |
|
||
| 尺寸 `size` | ✅ `large / middle / small` | ✅ `SizeType` 属性 | ✅ 完全对齐 |
|
||
| 变体 `variant` | ✅ `outlined / filled / borderless` | ✅ `StyleVariant` + `Underlined` | ✅ 超集(多 Underlined) |
|
||
| 状态 `status` | ✅ `error / warning` | ✅ `Status` 属性 | ✅ 完全对齐 |
|
||
| 允许清除 `allowClear` | ✅ | ✅ `IsAllowClear` | ✅ 完全对齐 |
|
||
| 占位文本 `placeholder` | ✅ | ✅ `PlaceholderText` | ✅ 完全对齐 |
|
||
| 禁用 `disabled` | ✅ | ✅ `IsEnabled` | ✅ 完全对齐 |
|
||
| 默认值 `defaultValue` | ✅ | ✅ `DefaultValue` | ✅ 完全对齐 |
|
||
| 过滤模式 `filterOption` | ✅ | ✅ `Filter` 属性 | ✅ 完全对齐 |
|
||
| 弹出位置 `placement` | ✅ `topLeft / bottomLeft` | ✅ `Placement`(Top / Bottom) | ✅ 基本对齐 |
|
||
| 下拉宽度匹配 `popupMatchSelectWidth` | ✅ | ✅ `IsPopupMatchSelectWidth` | ✅ 完全对齐 |
|
||
| 值变更 `onChange` | ✅ | ✅ `ValueChanged` 事件 | ✅ 完全对齐 |
|
||
| 选中变更 `onSelect` | ✅ | ✅ `SelectionChanged` 事件 | ✅ 完全对齐 |
|
||
| 搜索 `onSearch` | ✅ | ✅ `Populating` 事件 | ✅ 对齐(名称不同,语义一致) |
|
||
| 异步加载 | ✅ (通过 onSearch 手动实现) | ✅ `ICompleteOptionsAsyncLoader` | ✅ 增强(内置异步加载器抽象) |
|
||
| TextArea 集成 | ❌ 需手动组合 | ✅ `AutoCompleteTextArea` | ✅ AtomUI 增强 |
|
||
| Search 集成 | ❌ 需手动组合 | ✅ `AutoCompleteSearchEdit` | ✅ AtomUI 增强 |
|
||
| 回填 `autoComplete` | ✅ | ✅ `IsCompletionEnabled` | ✅ 完全对齐 |
|
||
| `open` / `onDropdownVisibleChange` | ✅ | ✅ `IsDropDownOpen` + 事件 | ✅ 完全对齐 |
|
||
|
||
---
|
||
|
||
## 继承关系
|
||
|
||
```
|
||
Avalonia.Controls.Primitives.TemplatedControl
|
||
└── AtomUI.Desktop.Controls.AbstractAutoComplete
|
||
├── implements ISizeTypeAware
|
||
├── implements IMotionAwareControl
|
||
├── implements IFormItemAware
|
||
├── implements IInputControlStatusAware
|
||
├── implements IInputControlStyleVariantAware
|
||
└── implements IFormItemFeedbackAware
|
||
└── AtomUI.Desktop.Controls.CompactSpaceAwareAutoComplete
|
||
├── implements ICompactSpaceAware
|
||
│ └── AtomUI.Desktop.Controls.AutoComplete
|
||
│ └── AtomUI.Desktop.Controls.AutoCompleteSearchEdit
|
||
└── AtomUI.Desktop.Controls.AutoCompleteTextArea
|
||
```
|
||
|
||
**各层级职责划分:**
|
||
|
||
| 层级 | 提供的能力 |
|
||
|---|---|
|
||
| `TemplatedControl` | Avalonia 模板化控件基础设施 |
|
||
| `AbstractAutoComplete` | 全部核心逻辑:候选列表管理、过滤、弹出/关闭、键盘导航、异步加载、表单集成、值管理 |
|
||
| `CompactSpaceAwareAutoComplete` | 紧凑空间适配能力(在 `Space.Compact` 中自动调整圆角和边框) |
|
||
| `AutoComplete` | 标准自动补全:使用 `LineEdit` 作为内嵌输入框 |
|
||
| `AutoCompleteSearchEdit` | 搜索型自动补全:使用 `SearchEdit` 作为内嵌输入框,增加搜索按钮相关属性 |
|
||
| `AutoCompleteTextArea` | 多行自动补全:使用 `TextArea` 作为内嵌输入框,增加多行相关属性,弹出位置跟随光标 |
|
||
|
||
**实现的共享接口:**
|
||
|
||
| 接口 | 定义位置 | 作用 |
|
||
|---|---|---|
|
||
| `ISizeTypeAware` | `AtomUI.Controls.Shared` | 支持 `SizeType`(Small / Middle / Large)三种尺寸切换 |
|
||
| `IMotionAwareControl` | `AtomUI.Controls.Shared` | 支持过渡动画开关 |
|
||
| `IFormItemAware` | `AtomUI.Controls.Shared` | 可作为 `FormItem` 的子控件参与表单验证 |
|
||
| `IFormItemFeedbackAware` | `AtomUI.Controls.Shared` | 支持表单验证反馈控件(如错误/警告图标) |
|
||
| `IInputControlStatusAware` | `AtomUI.Controls.Shared` | 支持 Error / Warning 验证状态 |
|
||
| `IInputControlStyleVariantAware` | `AtomUI.Controls.Shared` | 支持 Outline / Filled / Borderless / Underlined 样式变体 |
|
||
| `ICompactSpaceAware` | `AtomUI.Controls.Shared` | 在 `Space.Compact` 中使用时自动调整圆角和边框 |
|
||
|
||
---
|
||
|
||
## 源码位置
|
||
|
||
| 层级 | 文件路径 | 说明 |
|
||
|---|---|---|
|
||
| 核心基类 | `src/AtomUI.Desktop.Controls/AutoComplete/AbstractAutoComplete.cs` | 核心逻辑(候选管理、过滤、弹出、键盘导航) |
|
||
| 紧凑空间 | `src/AtomUI.Desktop.Controls/AutoComplete/CompactSpaceAwareAutoComplete.cs` | 紧凑空间适配中间类 |
|
||
| 标准控件 | `src/AtomUI.Desktop.Controls/AutoComplete/AutoComplete.cs` | 标准自动补全控件 |
|
||
| 搜索控件 | `src/AtomUI.Desktop.Controls/AutoComplete/AutoCompleteSearchEdit.cs` | 搜索型自动补全控件 |
|
||
| 多行控件 | `src/AtomUI.Desktop.Controls/AutoComplete/AutoCompleteTextArea.cs` | 多行文本自动补全控件 |
|
||
| 选项接口 | `src/AtomUI.Desktop.Controls/AutoComplete/IAutoCompleteOption.cs` | 候选选项接口 |
|
||
| 选项实现 | `src/AtomUI.Desktop.Controls/AutoComplete/AutoCompleteOption.cs` | 默认候选选项 record |
|
||
| 伪类常量 | `src/AtomUI.Desktop.Controls/AutoComplete/AutoCompletePseudoClass.cs` | 伪类定义 |
|
||
| Token 定义 | `src/AtomUI.Desktop.Controls/AutoComplete/AutoCompleteToken.cs` | 组件级 Design Token |
|
||
| 模板常量 | `src/AtomUI.Desktop.Controls/AutoComplete/AutoCompleteThemeConstants.cs` | 模板部件名称常量 |
|
||
| 异步加载 | `src/AtomUI.Desktop.Controls/AutoComplete/DataLoad/` | 异步加载器接口与结果模型 |
|
||
| 事件参数 | `src/AtomUI.Desktop.Controls/AutoComplete/CompleteValueChangedEventArgs.cs` | 值变更事件 |
|
||
| 事件参数 | `src/AtomUI.Desktop.Controls/AutoComplete/CompletePopulatingEventArgs.cs` | 填充开始事件 |
|
||
| 事件参数 | `src/AtomUI.Desktop.Controls/AutoComplete/CompletePopulatedEventArgs.cs` | 填充完成事件 |
|
||
| 主题模板 | `src/AtomUI.Desktop.Controls/AutoComplete/Themes/AutoCompleteTheme.axaml` | AutoComplete ControlTheme |
|
||
| 主题模板 | `src/AtomUI.Desktop.Controls/AutoComplete/Themes/AutoCompleteSearchEditTheme.axaml` | SearchEdit 变体 ControlTheme |
|
||
| 主题模板 | `src/AtomUI.Desktop.Controls/AutoComplete/Themes/AutoCompleteTextAreaTheme.axaml` | TextArea 变体 ControlTheme |
|
||
| 基础主题 | `src/AtomUI.Desktop.Controls/AutoComplete/Themes/AbstractAutoCompleteTheme.axaml` | 共享基础样式 |
|
||
| Gallery 示例 | `controlgallery/AtomUIGallery/ShowCases/Views/DataEntry/AutoCompleteShowCase.axaml` | 使用范例 |
|
||
|
||
---
|
||
|
||
## 模板结构
|
||
|
||
所有 AutoComplete 变体共享类似的模板结构,仅内嵌输入框类型不同:
|
||
|
||
```
|
||
Panel
|
||
├── InputBox (PART_TextBox) ← 内嵌输入框(LineEdit / SearchEdit / TextArea)
|
||
│ └── [输入框自身模板内容]
|
||
└── Popup (PART_Popup) ← 候选列表弹出层
|
||
└── Border#PopupFrame ← 弹出层框架(背景、圆角)
|
||
└── CandidateList (PART_CandidateList) ← 候选列表(单选模式)
|
||
└── [OptionTemplate 渲染每个候选项]
|
||
```
|
||
|
||
**分层设计理由:**
|
||
- **输入框独立**:输入框使用对应控件的完整主题(LineEdit / SearchEdit / TextArea),保持各自的视觉一致性。
|
||
- **弹出层独立**:Popup 使用 AtomUI 自定义实现,支持动画、点击外部关闭、Overlay 层等功能。
|
||
- **候选列表独立**:CandidateList 负责选项渲染和选择交互,与 AutoComplete 的核心逻辑通过事件解耦。
|
||
|
||
### 模板部件常量
|
||
|
||
| 常量名 | 值 | 说明 |
|
||
|---|---|---|
|
||
| `AutoCompleteThemeConstants.TextBoxPart` | `"PART_TextBox"` | 内嵌输入框 |
|
||
| `AutoCompleteThemeConstants.PopupPart` | `"PART_Popup"` | 候选列表弹出层 |
|
||
| `AutoCompleteThemeConstants.CandidateListPart` | `"PART_CandidateList"` | 候选列表 |
|