9.7 KiB
TreeView 自定义样式指南
TreeView 的视觉表现通过 ControlTheme + Design Token 系统控制。以下介绍几种常见的自定义方式。
1. 使用属性直接控制
最简单的方式是通过 TreeView 的公共属性来控制外观和行为:
<!-- 基本带复选框的树 -->
<atom:TreeView ToggleType="CheckBox">
<atom:TreeViewItem Header="parent 1" ItemKey="0-0">
<atom:TreeViewItem Header="child 1" ItemKey="0-0-0" />
<atom:TreeViewItem Header="child 2" ItemKey="0-0-1" />
</atom:TreeViewItem>
</atom:TreeView>
<!-- 显示连接线 + 图标 -->
<atom:TreeView IsShowLine="True"
IsShowIcon="True"
IsSwitcherRotation="False">
<atom:TreeViewItem Header="parent 1"
Icon="{antdicons:AntDesignIconProvider Kind=CarryOutOutlined}">
<atom:TreeViewItem Header="leaf"
Icon="{antdicons:AntDesignIconProvider Kind=CarryOutOutlined}" />
</atom:TreeViewItem>
</atom:TreeView>
<!-- Block 悬浮模式 -->
<atom:TreeView NodeHoverMode="Block"
IsDefaultExpandAll="True"
ToggleType="CheckBox">
<atom:TreeViewItem Header="parent">
<atom:TreeViewItem Header="child 1" IsEnabled="False" />
<atom:TreeViewItem Header="child 2" IsIndicatorEnabled="False" />
</atom:TreeViewItem>
</atom:TreeView>
<!-- 拖拽排序 -->
<atom:TreeView IsDraggable="True" NodeHoverMode="Block">
<atom:TreeViewItem Header="Item 1">
<atom:TreeViewItem Header="Sub Item 1" />
<atom:TreeViewItem Header="Sub Item 2" />
</atom:TreeViewItem>
<atom:TreeViewItem Header="Item 2" />
</atom:TreeView>
📖 完整示例参考:
controlgallery/AtomUIGallery/ShowCases/Views/DataDisplay/TreeViewShowCase.axaml
2. 通过 Style 覆盖样式
可以在 AXAML 中使用 Style 对 TreeView 和 TreeViewItem 进行全局或局部样式覆盖:
全局设置连接线和展开行为
<Window.Styles>
<Style Selector="atom|TreeView">
<Setter Property="IsShowLine" Value="True" />
<Setter Property="IsDefaultExpandAll" Value="True" />
</Style>
</Window.Styles>
自定义选中节点样式
<Style Selector="atom|TreeViewItem:selected">
<Setter Property="FontWeight" Value="Bold" />
</Style>
自定义勾选模式下的节点
<!-- 勾选模式下禁用的节点降低透明度 -->
<Style Selector="atom|TreeViewItem:toggle:disabled">
<Setter Property="Opacity" Value="0.5" />
</Style>
根据悬浮模式定制背景
<!-- Block 模式下增加额外内边距 -->
<Style Selector="atom|TreeView[NodeHoverMode=Block]">
<Setter Property="Padding" Value="4" />
</Style>
3. 自定义展开/折叠图标
通过 SwitcherRotationIcon、SwitcherExpandIcon、SwitcherCollapseIcon 属性自定义展开/折叠图标:
旋转图标模式
<atom:TreeView IsSwitcherRotation="True">
<atom:TreeView.SwitcherRotationIcon>
<atom:IconTemplate>
<antdicons:RightOutlined />
</atom:IconTemplate>
</atom:TreeView.SwitcherRotationIcon>
<atom:TreeViewItem Header="parent" ItemKey="0-0">
<atom:TreeViewItem Header="child 1" ItemKey="0-0-0" />
</atom:TreeViewItem>
</atom:TreeView>
替换图标模式
<atom:TreeView IsSwitcherRotation="False">
<atom:TreeView.SwitcherExpandIcon>
<atom:IconTemplate>
<antdicons:PlusSquareOutlined />
</atom:IconTemplate>
</atom:TreeView.SwitcherExpandIcon>
<atom:TreeView.SwitcherCollapseIcon>
<atom:IconTemplate>
<antdicons:MinusSquareOutlined />
</atom:IconTemplate>
</atom:TreeView.SwitcherCollapseIcon>
<!-- 节点... -->
</atom:TreeView>
📖 参考:
controlgallery/AtomUIGallery/ShowCases/Views/DataDisplay/TreeViewShowCase.axaml中 "Customize collapse/expand icon" 示例。
4. 通过 TreeDataTemplate 数据绑定
使用 ItemsSource + TreeDataTemplate 实现 MVVM 数据驱动:
<atom:TreeView Name="MyTreeView" ToggleType="CheckBox">
<atom:TreeView.ItemTemplate>
<TreeDataTemplate ItemsSource="{Binding Children}">
<atom:TextBlock Text="{Binding Header}" />
</TreeDataTemplate>
</atom:TreeView.ItemTemplate>
</atom:TreeView>
// Code-behind 或 ViewModel
myTreeView.ItemsSource = new List<TreeItemNode>
{
new TreeItemNode()
{
Header = "parent 1",
ItemKey = "0-0",
Children = [
new TreeItemNode() { Header = "leaf 1", ItemKey = "0-0-0" },
new TreeItemNode() { Header = "leaf 2", ItemKey = "0-0-1" }
]
}
};
📖 参考:
controlgallery/AtomUIGallery/ShowCases/Views/DataDisplay/TreeViewShowCase.axaml中 "Generate by template" 示例。
5. 搜索过滤示例
通过配合 SearchEdit 实现树节点搜索:
<StackPanel Orientation="Vertical" Spacing="10">
<atom:SearchEdit PlaceholderText="Search"
SearchButtonClick="HandleFilterTreeClicked" />
<atom:TreeView Name="SearchTreeView">
<atom:TreeViewItem Header="0-0">
<atom:TreeViewItem Header="0-0-0">
<atom:TreeViewItem Header="0-0-0-0" />
</atom:TreeViewItem>
</atom:TreeViewItem>
</atom:TreeView>
</StackPanel>
private void HandleFilterTreeClicked(object? sender, RoutedEventArgs e)
{
if (sender is SearchEdit searchEdit)
{
SearchTreeView.FilterValue = searchEdit.Text?.Trim();
}
}
📖 参考:
controlgallery/AtomUIGallery/ShowCases/Views/DataDisplay/TreeViewShowCase.axaml中 "Searchable" 示例。
6. 异步加载示例
通过 DataLoader 实现展开时异步加载子节点:
<atom:TreeView Name="AsyncLoadTree">
<atom:TreeView.ItemTemplate>
<TreeDataTemplate ItemsSource="{Binding Children}">
<atom:TextBlock Text="{Binding Header}" />
</TreeDataTemplate>
</atom:TreeView.ItemTemplate>
</atom:TreeView>
// 初始化数据
AsyncLoadTree.ItemsSource = new List<TreeItemNode>
{
new TreeItemNode() { Header = "Expand to load", ItemKey = "0" },
new TreeItemNode() { Header = "Expand to load", ItemKey = "1" },
new TreeItemNode() { Header = "Tree Node", ItemKey = "2", IsLeaf = true }
};
// 设置加载器
AsyncLoadTree.DataLoader = new TreeItemDataLoader();
// 自定义加载器实现
public class TreeItemDataLoader : ITreeItemNodeLoader
{
public async Task<TreeItemLoadResult> LoadAsync(ITreeItemNode targetTreeItem, CancellationToken token)
{
await Task.Delay(1000, token); // 模拟异步加载
return new TreeItemLoadResult
{
IsSuccess = true,
Data = new List<ITreeItemNode>
{
new TreeItemNode() { Header = "Child 1", ItemKey = "child-1" },
new TreeItemNode() { Header = "Child 2", ItemKey = "child-2", IsLeaf = true }
}.AsReadOnly()
};
}
}
📖 参考:
controlgallery/AtomUIGallery/ShowCases/Views/DataDisplay/TreeViewShowCase.axaml中 "load data asynchronously" 示例。
7. 默认展开和选中路径
通过路径指定初始展开、选中和勾选状态:
// 默认展开路径
myTreeView.DefaultExpandedPaths = new List<TreeNodePath>
{
new TreeNodePath("0-0/0-0-0"),
new TreeNodePath("0-0/0-0-1/0-0-1-1")
};
// 默认选中路径
myTreeView.DefaultSelectedPaths = new List<TreeNodePath>
{
new TreeNodePath("0-0/0-0-1")
};
// 默认勾选路径
myTreeView.DefaultCheckedPaths = new List<TreeNodePath>
{
new TreeNodePath("0-0/0-0-1/0-0-1-1")
};
📖 参考:
controlgallery/AtomUIGallery/ShowCases/Views/DataDisplay/TreeViewShowCase.axaml.cs中InitBasicTreeViewData方法。
8. 控制动画行为
<!-- 禁用展开/折叠动画 -->
<atom:TreeView IsMotionEnabled="False">
<!-- 节点... -->
</atom:TreeView>
// 代码中全部展开(不带动画)
myTreeView.ExpandAll(motionEnabled: false);
// 代码中全部展开(带动画)
myTreeView.ExpandAll(motionEnabled: true);
样式选择器速查
说明:Avalonia 样式选择器中使用
atom|TreeView语法引用atomXML 命名空间下的类型,其中|是命名空间分隔符。
TreeView 选择器
| 选择器 | 说明 |
|---|---|
atom|TreeView |
匹配所有 AtomUI TreeView 实例 |
atom|TreeView:draggable |
匹配启用了拖拽功能的 TreeView |
atom|TreeView[NodeHoverMode=Block] |
匹配 Block 悬浮模式的 TreeView |
atom|TreeView[NodeHoverMode=WholeLine] |
匹配 WholeLine 悬浮模式的 TreeView |
atom|TreeView[IsShowLine=True] |
匹配显示连接线的 TreeView |
atom|TreeView:disabled |
匹配禁用状态的 TreeView |
TreeViewItem 选择器
| 选择器 | 说明 |
|---|---|
atom|TreeViewItem |
匹配所有树节点 |
atom|TreeViewItem:selected |
匹配选中的节点 |
atom|TreeViewItem:expanded |
匹配展开的节点 |
atom|TreeViewItem:checked |
匹配勾选的节点 |
atom|TreeViewItem:toggle |
匹配 CheckBox 勾选模式的节点 |
atom|TreeViewItem:radio |
匹配 Radio 单选模式的节点 |
atom|TreeViewItem:disabled |
匹配禁用的节点 |
atom|TreeViewItem:pointerover |
匹配鼠标悬浮的节点 |
组合选择器示例
| 选择器 | 说明 |
|---|---|
atom|TreeViewItem:selected:not(:disabled) |
非禁用状态下已选中的节点 |
atom|TreeViewItem:toggle:checked |
CheckBox 模式下已勾选的节点 |
atom|TreeView[IsShowLine=True] atom|TreeViewItem:expanded |
显示连接线的 TreeView 中展开的节点 |
atom|TreeViewItem /template/ atom|TreeViewItemHeader |
访问节点模板内的标题区域 |