# 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` 集合: ```csharp autoComplete.OptionsSource = new List { new AutoCompleteOption { Header = "选项一", Content = "选项一" }, new AutoCompleteOption { Header = "选项二", Content = "选项二" }, }; ``` **2. 异步数据加载(`OptionsAsyncLoader`)** 实现 `ICompleteOptionsAsyncLoader` 接口,根据用户输入动态加载候选数据: ```csharp public class MyLoader : ICompleteOptionsAsyncLoader { public async Task 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"` | 候选列表 |