Files
AtomUI/docs/Desktop.Controls/TreeView/TreeView.md
T

18 KiB
Raw Blame History

TreeView 树形控件

概述

树形控件(TreeView)用于展示具有层级关系的数据结构。它支持节点的展开/折叠、复选框勾选、拖拽排序、搜索过滤、异步加载等功能,是文件浏览器、组织架构、分类目录等场景中最常见的数据展示控件之一。

AtomUI 的 TreeView 控件对齐了 Ant Design 5.0 Tree 的设计规范,在 .NET / Avalonia 平台上提供与 Ant Design React 版一致的视觉体验和交互行为。


设计原理

Ant Design 的树形控件设计哲学

Ant Design 对树形控件的定位是:「展示具有层级关系的信息,可支持展开收起、复选等交互」。树形控件承载两类核心需求:

  1. 数据展示:将具有父子关系的数据以可视化的层级结构呈现,帮助用户理解数据的组织方式。
  2. 交互操作:支持节点选中(单选/多选)、勾选(Checkbox)、展开/折叠、拖拽重排、搜索过滤等丰富的交互模式。

核心功能特性:

功能 设计意图 典型场景
📁 展开/折叠 按需展示层级数据,减少视觉负担 文件目录、组织架构
☑️ 复选框(Checkable) 对树节点进行批量勾选,支持父子联动 权限配置、分类筛选
🔘 单选按钮(Radio) 对同一层级节点进行单选 分组选择
🖱️ 拖拽排序(Draggable) 通过拖放调整节点位置和层级关系 菜单编排、目录管理
🔍 搜索过滤 快速定位匹配节点并高亮显示 大量节点中快速查找
⏳ 异步加载 展开节点时按需加载子节点数据 大数据量、远程数据源
➖ 连接线(ShowLine) 用连接线展示节点间的层级关系 增强视觉层级感
🎨 自定义图标 为每个节点设置自定义图标 文件类型区分、状态标识

三种悬浮高亮模式:

模式 设计意图
Default 仅高亮节点文字区域(默认模式)
Block 高亮整个节点行(包含缩进区域),增强视觉反馈
WholeLine 高亮整行(从容器左边缘到右边缘),适合目录风格

Avalonia TreeView 基础能力

AtomUI 的 TreeView 继承自 Avalonia 框架的 Avalonia.Controls.TreeView。理解 Avalonia TreeView 的基础能力有助于理解 AtomUI 在其之上做了哪些扩展。

Avalonia TreeView 的核心职责:

Avalonia 的 TreeView 是一个 ItemsControl 的子类,用于以树形结构展示层级数据。其继承链为:

Control → TemplatedControl → ItemsControl → SelectingItemsControl → TreeView

作为 ItemsControl,TreeView 可以通过 Items 集合直接添加 TreeViewItem,也可以通过 ItemsSource + ItemTemplate / TreeDataTemplate 进行数据绑定。Avalonia TreeView 提供了基础的选择模型(SelectedItem / SelectedItems / SelectionMode)以及节点容器化管理。

Avalonia TreeView 提供的基础属性:

属性 说明
Items 直接添加 TreeViewItem 子节点
ItemsSource 数据绑定源
ItemTemplate 项模板(TreeDataTemplate 支持层级绑定)
SelectedItem 当前选中项
SelectedItems 选中项集合(多选模式)
SelectionMode 选择模式(Single / Multiple / Toggle)

Avalonia TreeViewItem 提供的基础属性:

属性 说明
Header 节点标题内容
HeaderTemplate 标题模板
IsExpanded 节点是否展开
IsSelected 节点是否选中
Level 节点层级(只读,自动计算)
Items 子节点集合

AtomUI 的扩展设计

AtomUI TreeView 在 Avalonia TreeView 的基础上,遵循 Ant Design 5.0 规范做了以下扩展:

扩展能力 实现方式 设计动机
复选框勾选 ToggleType 枚举 + IsChecked 三态属性 对齐 Ant Design 的 checkable,支持 CheckBox 和 Radio 两种模式
父子联动 IsCheckStrictly 属性 + 递归勾选算法 勾选父节点自动勾选所有子节点,取消时反之
拖拽排序 IsDraggable 属性 + 拖拽指示线渲染 对齐 Ant Design 的 draggable,支持拖放重排节点
搜索过滤 Filter + FilterValue + FilterHighlightStrategy 对齐 Ant Design 的搜索功能,支持高亮匹配、隐藏未匹配等策略
异步加载 DataLoader + ITreeItemNodeLoader 接口 对齐 Ant Design 的 loadData,展开时按需加载子节点
连接线 IsShowLine 属性 + OnRender 自绘 对齐 Ant Design 的 showLine,绘制节点间连接线
悬浮模式 NodeHoverMode 三种模式 不同场景下的悬浮高亮效果
节点图标 IsShowIcon / IsShowLeafIcon + PathIcon 对齐 Ant Design 的 showIcon,支持自定义节点图标
自定义开关图标 SwitcherExpandIcon / SwitcherCollapseIcon 等 对齐 Ant Design 的 switcherIcon,支持替换展开/折叠图标
展开/折叠动画 IsMotionEnabled + ExpandMotion / CollapseMotion 展开/折叠带缓动动画,提升交互体验
默认路径 DefaultExpandedPaths / DefaultSelectedPaths / DefaultCheckedPaths 对齐 Ant Design 的 defaultExpandedKeys 等,通过路径指定初始状态
空数据提示 EmptyIndicator / IsShowEmptyIndicator 当无数据时展示空状态指示器
表单集成 IFormItemAware 接口 可参与 FormItem 验证流程
Design Token TreeViewToken + RegisterTokenResourceScope 所有视觉值从全局/组件级 Token 派生

功能详解

节点展开与折叠

TreeView 支持多种方式控制节点展开状态:

  • 手动展开:点击节点前的展开/折叠图标(Switcher)
  • 全部展开:设置 IsDefaultExpandAll="True" 或调用 ExpandAll() 方法
  • 全部折叠:调用 CollapseAll() 方法
  • 路径展开:通过 DefaultExpandedPaths 指定初始展开路径
  • 自动展开父节点:设置 IsAutoExpandParent="True"(默认值),选中子节点时自动展开其父节点

展开/折叠带有缓动动画(ExpandMotion / CollapseMotion),可通过 IsMotionEnabled 属性控制是否启用。

复选框勾选(ToggleType)

通过 ToggleType 属性启用节点勾选功能:

ToggleType 行为
None 不显示勾选控件(默认)
CheckBox 显示 CheckBox,支持三态(选中/半选/未选)
Radio 显示 Radio,同组内单选

父子联动机制(IsCheckStrictly == false 时,默认行为):

  • 勾选父节点 → 递归勾选所有可勾选子节点
  • 取消父节点 → 递归取消所有子节点
  • 子节点全部勾选 → 父节点自动变为「选中」状态
  • 子节点部分勾选 → 父节点自动变为「半选」(Indeterminate)状态
  • 子节点全部取消 → 父节点自动变为「未选」状态

设置 IsCheckStrictly="True" 可关闭父子联动,每个节点独立勾选。

拖拽排序(IsDraggable)

设置 IsDraggable="True" 启用拖拽功能:

  • 拖动时显示拖拽预览浮层(DragPreviewAdorner)
  • 拖拽过程中渲染指示线,指示插入位置(上方/下方/内部)
  • 不允许将父节点拖入自身子节点中(防止循环引用)
  • 拖拽完成后自动调整节点位置

拖拽提供完整的事件回调:ItemDragStarted、ItemDragEnter、ItemDragLeave、ItemDragOver、ItemDragCompleted、ItemDropped。

搜索过滤(Filter)

TreeView 内置搜索过滤功能,通过设置 FilterValue 触发过滤:

  1. 设置 Filter 属性(默认使用 DefaultTreeItemFilter,按 Header 文本匹配)
  2. 设置 FilterValue 为搜索关键词
  3. 通过 FilterHighlightStrategy 控制过滤行为

过滤高亮策略(TreeFilterHighlightStrategy,可组合):

策略 说明
HighlightedMatch 高亮匹配文本
HighlightedWhole 高亮整个匹配节点
BoldedMatch 加粗匹配文本
ExpandPath 自动展开匹配节点的祖先路径
HideUnMatched 隐藏未匹配的节点
All 以上全部(默认)

异步加载(DataLoader)

通过 DataLoader 属性设置异步数据加载器:

  • 必须使用 ItemsSource 绑定数据(不支持手动添加 TreeViewItem 模式)
  • 展开非叶子节点时自动调用 ITreeItemNodeLoader.LoadAsync()
  • 加载过程中节点显示旋转 Loading 图标
  • 设置 TreeItemNode.IsLeaf = true 的节点不会触发加载

连接线(ShowLine)

设置 IsShowLine="True" 启用节点间连接线:

  • 连接线通过 TreeViewItem.Render() 自绘,使用 BorderBrush 颜色
  • IsSwitcherRotation 控制展开/折叠图标是旋转动画还是替换图标
  • 当 IsShowLine="True" 时建议设置 IsSwitcherRotation="False",使用展开/折叠两个不同图标

空数据指示器

当 TreeView 无数据(Items 为空或过滤无结果)时:

  • IsShowEmptyIndicator="True"(默认启用)自动显示空状态指示器
  • 可通过 EmptyIndicator / EmptyIndicatorTemplate 自定义空状态内容

与 Ant Design 规范的对齐程度

特性 Ant Design (React) AtomUI (Avalonia) 对齐情况
展开/折叠 ✅ 基础能力 ✅ IsExpanded + 动画 ✅ 完全对齐
复选框 checkable ✅ checkable 属性 ✅ ToggleType=CheckBox ✅ 完全对齐
父子联动 checkStrictly ✅ checkStrictly ✅ IsCheckStrictly ✅ 完全对齐
拖拽 draggable ✅ draggable ✅ IsDraggable ✅ 完全对齐
连接线 showLine ✅ showLine ✅ IsShowLine ✅ 完全对齐
节点图标 showIcon ✅ showIcon ✅ IsShowIcon ✅ 完全对齐
默认展开 defaultExpandAll ✅ defaultExpandAll ✅ IsDefaultExpandAll ✅ 完全对齐
默认展开键 defaultExpandedKeys ✅ 按 key 指定 ✅ DefaultExpandedPaths ✅ 对齐(使用路径而非 key)
默认选中键 defaultSelectedKeys ✅ 按 key 指定 ✅ DefaultSelectedPaths ✅ 对齐(使用路径而非 key)
默认勾选键 defaultCheckedKeys ✅ 按 key 指定 ✅ DefaultCheckedPaths ✅ 对齐(使用路径而非 key)
异步加载 loadData ✅ 回调函数 ✅ DataLoader + ITreeItemNodeLoader ✅ 对齐(接口模式)
搜索过滤 ✅ filterTreeNode ✅ Filter + FilterValue ✅ 完全对齐
自定义开关图标 switcherIcon ✅ ReactNode ✅ SwitcherExpandIcon 等 ✅ 对齐
Block 节点 blockNode ✅ blockNode ✅ NodeHoverMode=Block ✅ 对齐
虚拟滚动 virtual ✅ 虚拟列表 ❌ 暂未支持 ⚠️ 待支持
目录模式 Tree.DirectoryTree ✅ 独立组件 ❌ 暂未提供 ⚠️ 可通过样式模拟

继承关系

Avalonia.Controls.Primitives.TemplatedControl
  └── Avalonia.Controls.ItemsControl
        └── Avalonia.Controls.SelectingItemsControl
              └── Avalonia.Controls.TreeView
                    └── AtomUI.Desktop.Controls.TreeView
                          ├── implements IMotionAwareControl
                          └── implements IFormItemAware

TreeView 通过 using AvaloniaTreeView = Avalonia.Controls.TreeView; 别名引用 Avalonia 原生 TreeView,避免类名冲突。

各层级职责划分:

层级 提供的能力
ItemsControl Items 集合管理、ItemsSource 数据绑定、ItemTemplate 模板化
SelectingItemsControl 选择模型(SelectedItem / SelectedItems / SelectionMode)、选择事件
Avalonia.Controls.TreeView 树形容器化管理、TreeViewItem 容器创建、展开/折叠基础逻辑
AtomUI.Desktop.Controls.TreeView Ant Design 视觉体系(连接线/图标/悬浮模式)、CheckBox/Radio 勾选、拖拽排序、搜索过滤、异步加载、默认路径、Design Token 集成、展开折叠动画、空数据指示器、表单集成

实现的共享接口:

接口 定义位置 作用
IMotionAwareControl AtomUI.Controls.Shared 支持 IsMotionEnabled 动画开关
IFormItemAware AtomUI.Controls.Shared 可作为 FormItem 的子控件参与表单验证

关联类型

TreeViewItem

TreeViewItem 是 TreeView 的节点容器控件,继承自 Avalonia.Controls.TreeViewItem,实现了 IRadioButton 和 ITreeItemNode 接口。

Avalonia.Controls.Primitives.TemplatedControl
  └── Avalonia.Controls.ContentControl (HeaderedItemsControl)
        └── Avalonia.Controls.TreeViewItem
              └── AtomUI.Desktop.Controls.TreeViewItem
                    ├── implements IRadioButton
                    └── implements ITreeItemNode

每个 TreeViewItem 代表树中的一个节点,支持:

  • 标题内容(Header)
  • 图标(Icon)
  • 三态勾选(IsChecked)
  • 叶子节点标识(IsLeaf)
  • 加载状态(IsLoading)
  • 节点值(Value)
  • 指示器启用(IsIndicatorEnabled)
  • 节点唯一标识(ItemKey)

ITreeItemNode

树节点数据接口,用于数据绑定模式下描述节点数据。继承自 ITreeNode<ITreeItemNode>。

public interface ITreeItemNode : ITreeNode<ITreeItemNode>
{
    bool? IsChecked { get; set; }
    bool IsSelected { get; set; }
    bool IsExpanded { get; set; }
    bool IsIndicatorEnabled { get; set; }
    string? GroupName { get; }
    bool IsLeaf { get; }
    object? Value { get; set; }
    bool IsEnabled { get; set; }
    void UpdateParentNode(ITreeItemNode? parentNode);
}

TreeItemNode

ITreeItemNode 的默认实现(record 类型),支持声明式初始化和父子关系自动维护。当向 Children 集合添加子节点时,会自动设置 ParentNode。

ITreeItemNodeLoader

异步数据加载器接口,用于展开节点时按需加载子节点数据。

public interface ITreeItemNodeLoader
{
    Task<TreeItemLoadResult> LoadAsync(ITreeItemNode targetTreeItem, CancellationToken token);
}

ITreeItemFilter

自定义过滤器接口,用于控制树节点的搜索匹配逻辑。

public interface ITreeItemFilter
{
    bool Filter(TreeView treeView, TreeViewItem treeViewItem, object? filterValue);
}

FloatableTreeView

TreeView 的子类,额外支持 TreeViewFlyout 弹出层集成,用于下拉树选择器(如 TreeSelect)等场景。提供 IsOpen、Opened、Closed 等弹出状态管理。


源码位置

层级 文件路径 说明
控件类(主文件) src/AtomUI.Desktop.Controls/TreeView/TreeView.cs TreeView 主类
控件类(过滤) src/AtomUI.Desktop.Controls/TreeView/TreeView.Filter.cs 搜索过滤相关逻辑
控件类(异步加载) src/AtomUI.Desktop.Controls/TreeView/TreeView.AsyncItemDataLoad.cs 异步加载逻辑
控件类(拖拽) src/AtomUI.Desktop.Controls/TreeView/TreeView.DragAndDrop.cs 拖拽排序逻辑
节点控件 src/AtomUI.Desktop.Controls/TreeView/TreeViewItem.cs 树节点容器控件
节点数据接口 src/AtomUI.Desktop.Controls/TreeView/ITreeItemNode.cs 节点数据接口定义
节点数据实现 src/AtomUI.Desktop.Controls/TreeView/TreeItemNode.cs 节点数据默认实现
浮动树 src/AtomUI.Desktop.Controls/TreeView/FloatableTreeView.cs 弹出层集成
过滤接口 src/AtomUI.Desktop.Controls/TreeView/ITreeItemFilter.cs 自定义过滤器接口
伪类常量 src/AtomUI.Desktop.Controls/TreeView/TreeViewPseudoClass.cs 伪类定义
Token 定义 src/AtomUI.Desktop.Controls/TreeView/TreeViewToken.cs 组件级 Design Token
异步加载接口 src/AtomUI.Desktop.Controls/TreeView/DataLoad/ITreeItemNodeLoader.cs 数据加载器接口
加载结果 src/AtomUI.Desktop.Controls/TreeView/DataLoad/TreeItemLoadResult.cs 加载结果模型
事件参数 src/AtomUI.Desktop.Controls/TreeView/EventArgs/ 各类事件参数定义
主题模板 src/AtomUI.Desktop.Controls/TreeView/Themes/TreeViewTheme.axaml ControlTheme AXAML
主题代码 src/AtomUI.Desktop.Controls/TreeView/Themes/TreeViewTheme.cs 主题 code-behind
模板常量 src/AtomUI.Desktop.Controls/TreeView/Themes/TreeViewThemeConstants.cs 模板部件名称常量
Gallery 示例 controlgallery/AtomUIGallery/ShowCases/Views/DataDisplay/TreeViewShowCase.axaml 使用范例

模板结构

TreeView 的模板由三层组成:

TreeView 模板

Border#Frame                                ← 主框架(承载背景、边框)
└── ScrollViewer                            ← 滚动容器
    └── ItemsPresenter                      ← 节点列表

TreeViewItem 模板

Panel                                       ← 节点根面板
├── TreeViewItemHeader (Header)             ← 节点标题区域
│   ├── NodeSwitcherButton (PART_NodeSwitcherButton) ← 展开/折叠按钮
│   ├── CheckBox / RadioButton               ← 勾选控件(由 ToggleType 决定)
│   ├── IconPresenter (PART_IconPresenter)   ← 节点图标
│   └── ContentPresenter                     ← 标题内容
└── BaseMotionActor (PART_ItemsPresenterMotionActor) ← 子节点容器(带动画)
    └── ItemsPresenter                       ← 子节点列表

模板部件常量

常量名 值 说明
TreeViewItemThemeConstants.ItemsPresenterMotionActorPart "PART_ItemsPresenterMotionActor" 子节点动画容器
TreeViewItemHeaderThemeConstants.IconPresenterPart "PART_IconPresenter" 图标展示器
TreeViewItemHeaderThemeConstants.NodeSwitcherButtonPart "PART_NodeSwitcherButton" 展开/折叠按钮
TreeViewItemHeaderThemeConstants.HeaderContentFramePart "PART_HeaderContentFrame" 标题内容框架