Files

16 KiB
Raw Permalink Blame History

TreeSelect 使用文档

本文档介绍 AtomUI TreeSelect 控件的各种使用方式,示例代码摘自 Gallery 演示程序。

📖 Gallery 源码位置:controlgallery/AtomUIGallery/ShowCases/Views/DataEntry/TreeSelectShowCase.axaml


前置准备

在 AXAML 中使用 TreeSelect,需要引入以下命名空间:

xmlns:atom="https://atomui.net"
xmlns:antdicons="https://atomui.net/icons/antdesign"

在 C# 代码中引入:

using AtomUI.Desktop.Controls;   // TreeSelect 控件
using AtomUI.Controls;            // SizeType, ITreeItemNode, TreeItemNode 等共享类型

1. 基本用法(单选)

最基本的 TreeSelect 使用方式——单选模式,点击节点即选中,弹窗自动关闭。

<atom:TreeSelect Name="BasicTreeSelect"
                 HorizontalAlignment="Stretch"
                 IsDefaultExpandAll="True"
                 IsAllowClear="True"
                 IsFilterEnabled="True"
                 PlaceholderText="Please select" />
// Code-behind:构建树形数据源
var treeNodes = new List<TreeItemNode>
{
    new TreeItemNode()
    {
        Header = "parent 1",
        Value  = "parent 1",
        Children = [
            new TreeItemNode()
            {
                Header = "parent 1-0",
                Value  = "parent 1-0",
                Children = [
                    new TreeItemNode() { Header = "leaf1", Value = "leaf1" },
                    new TreeItemNode() { Header = "leaf2", Value = "leaf2" },
                ]
            },
            new TreeItemNode()
            {
                Header = "parent 1-1",
                Value  = "parent 1-1",
                Children = [
                    new TreeItemNode() { Header = "leaf11", Value = "leaf11" }
                ]
            }
        ]
    }
};

BasicTreeSelect.ItemsSource = treeNodes;

要点:

  • IsDefaultExpandAll="True" 使所有节点默认展开
  • IsAllowClear="True" 在选中后显示清除按钮
  • IsFilterEnabled="True" 启用搜索筛选功能

2. 多选模式

设置 IsMultiple="True" 启用多选模式,选中项以 Tag 形式展示在输入框中。

<atom:TreeSelect Name="MultiSelectionTreeSelect"
                 HorizontalAlignment="Stretch"
                 IsDefaultExpandAll="True"
                 IsAllowClear="True"
                 IsFilterEnabled="True"
                 IsMultiple="True"
                 PlaceholderText="Please select" />
vm.MultiSelectionTreeNodes = new List<TreeItemNode>
{
    new TreeItemNode()
    {
        Header = "parent 1",
        Value  = "parent 1",
        Children = [
            new TreeItemNode()
            {
                Header = "parent 1-0",
                Value  = "parent 1-0",
                Children = [
                    new TreeItemNode() { Header = "my leaf", Value = "leaf1" },
                    new TreeItemNode() { Header = "your leaf", Value = "leaf2" }
                ]
            },
            new TreeItemNode()
            {
                Header = "parent 1-1",
                Value  = "parent 1-1",
                Children = [
                    new TreeItemNode() { Header = "sss", Value = "sss" }
                ]
            }
        ]
    },
};

3. 通过 ItemsSource 绑定数据

使用 ItemsSource 属性绑定树形数据源是推荐的 MVVM 数据驱动方式:

<atom:TreeSelect Name="ItemsSourceTreeSelect"
                 HorizontalAlignment="Stretch"
                 IsDefaultExpandAll="True"
                 IsAllowClear="True"
                 IsFilterEnabled="True"
                 PlaceholderText="Please select" />
// 使用 ReactiveUI 绑定
this.OneWayBind(ViewModel, vm => vm.TreeNodes, v => v.ItemsSourceTreeSelect.ItemsSource)
    .DisposeWith(disposables);
// ViewModel
vm.TreeNodes = new List<TreeItemNode>
{
    new TreeItemNode()
    {
        Header = "Node1",
        Value  = "0-0",
        Children = [
            new TreeItemNode() { Header = "Child Node1", Value = "0-0-1" },
            new TreeItemNode() { Header = "Child Node2", Value = "0-0-2" }
        ]
    },
    new TreeItemNode()
    {
        Header = "Node2",
        Value  = "0-1",
    }
};

4. 勾选模式(Checkable)

设置 IsTreeCheckable="True" 启用 Checkbox 勾选模式,支持父子联动。配合 ShowCheckedStrategy 控制展示策略。

<atom:TreeSelect Name="CheckableTreeSelect"
                 HorizontalAlignment="Stretch"
                 IsDefaultExpandAll="True"
                 IsAllowClear="True"
                 IsFilterEnabled="True"
                 IsTreeCheckable="True"
                 PlaceholderText="Please select"
                 ShowCheckedStrategy="ShowParent" />
vm.CheckableTreeNodes = new List<TreeItemNode>
{
    new TreeItemNode()
    {
        Header = "Node1",
        ItemKey = "0-0",
        Children = [
            new TreeItemNode() { Header = "Child Node1", Value = "0-0-0" }
        ]
    },
    new TreeItemNode()
    {
        Header = "Node2",
        ItemKey = "0-1",
        Children = [
            new TreeItemNode() { Header = "Child Node3", Value = "0-1-0" },
            new TreeItemNode()
            {
                Header = "Child Node4",
                Value  = "0-1-1",
                Children = [
                    new TreeItemNode() { Header = "Child Node6", Value = "0-1-1-0" },
                    new TreeItemNode() { Header = "Child Node7", Value = "0-1-1-1" },
                ]
            },
            new TreeItemNode() { Header = "Child Node5", Value = "0-1-2" }
        ]
    }
};

勾选策略说明:

  • ShowCheckedStrategy="All":展示所有勾选节点
  • ShowCheckedStrategy="ShowParent":当所有子节点都勾选时仅展示父节点
  • ShowCheckedStrategy="ShowChild":仅展示叶子节点

5. 异步加载

通过 DataLoader 属性提供异步加载器,实现展开节点时按需加载子节点:

<atom:TreeSelect Name="AsyncLoadTreeSelect"
                 HorizontalAlignment="Stretch"
                 IsAllowClear="True"
                 PlaceholderText="Please select" />
// 初始化根节点
vm.AsyncLoadTreeNodes = 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 }
};

// 绑定异步加载器
vm.AsyncLoadTreeNodeLoader = new TreeItemDataLoader();
this.OneWayBind(ViewModel, vm => vm.AsyncLoadTreeNodeLoader, v => v.AsyncLoadTreeSelect.DataLoader)
    .DisposeWith(disposables);
// 自定义加载器实现 ITreeItemNodeLoader 接口
public class TreeItemDataLoader : ITreeItemNodeLoader
{
    public async Task<IList<ITreeItemNode>> LoadChildrenAsync(ITreeItemNode parentNode, CancellationToken cancellationToken)
    {
        await Task.Delay(1000, cancellationToken); // 模拟异步加载
        return new List<ITreeItemNode>
        {
            new TreeItemNode() { Header = $"Child of {parentNode.Header}", Value = "child-1" },
            new TreeItemNode() { Header = $"Another child", Value = "child-2", IsLeaf = true }
        };
    }
}

要点:非叶子节点展开时自动调用 DataLoader,加载过程中显示旋转图标。设置 IsLeaf = true 的节点不会触发加载。


6. 弹窗位置

通过 Placement 属性和 IsPopupMatchSelectWidth 属性控制弹窗弹出位置:

<atom:TreeSelect Name="PlacementTreeSelect"
                 IsAllowClear="True"
                 PlaceholderText="Please select"
                 IsDefaultExpandAll="True"
                 IsFilterEnabled="True"
                 IsPopupMatchSelectWidth="False"
                 Placement="{Binding Placement}" />
// ViewModel 中动态切换弹窗位置
public void HandlePlacementOptionCheckedChanged(object? sender, OptionCheckedChangedEventArgs args)
{
    if (args.Index == 0)
        vm.Placement = SelectPopupPlacement.TopEdgeAlignedLeft;
    else if (args.Index == 1)
        vm.Placement = SelectPopupPlacement.TopEdgeAlignedRight;
    else if (args.Index == 2)
        vm.Placement = SelectPopupPlacement.BottomEdgeAlignedLeft;
    else
        vm.Placement = SelectPopupPlacement.BottomEdgeAlignedRight;
}

📖 参考:controlgallery/AtomUIGallery/ShowCases/Views/DataEntry/TreeSelectShowCase.axaml 中 "Placement" 示例。


7. 显示树线

通过 IsShowLine、IsShowIcon、IsShowLeafIcon、IsSwitcherRotation 属性控制树形结构的视觉展示:

<atom:ToggleSwitch OnContent="ShowIcon" OffContent="ShowIcon" Name="ShowIconSwitch" />
<atom:ToggleSwitch OnContent="TreeLine" OffContent="TreeLine" IsChecked="True"
                   Name="ShowTreeLineSwitch" />
<atom:ToggleSwitch OnContent="ShowLeafIcon" OffContent="ShowLeafIcon" Name="ShowLeafIconSwitch" />

<atom:TreeSelect Name="ShowTreeLineTreeSelect"
                 HorizontalAlignment="Stretch"
                 IsAllowClear="True"
                 PlaceholderText="Please select"
                 IsShowIcon="{Binding #ShowIconSwitch.IsChecked}"
                 IsShowLeafIcon="{Binding #ShowLeafIconSwitch.IsChecked}"
                 IsShowLine="{Binding #ShowTreeLineSwitch.IsChecked}"
                 IsSwitcherRotation="{Binding #ShowTreeLineSwitch.IsChecked,
                                      Converter={x:Static BoolConverters.Not}}" />
// 数据中可以为节点指定图标
vm.ShowTreeLineTreeNodes = new List<TreeItemNode>
{
    new TreeItemNode()
    {
        Header = "parent 1",
        ItemKey = "parent 1",
        Children = [
            new TreeItemNode()
            {
                Header = "parent 1-0",
                Value  = "parent 1-0",
                Icon   = new CarryOutOutlined(),
                Children = [
                    new TreeItemNode()
                    {
                        Header  = "Leaf1",
                        ItemKey = "Leaf1",
                        IsLeaf  = true,
                        Icon    = new CarryOutOutlined(),
                    }
                ]
            }
        ]
    }
};

📖 参考:controlgallery/AtomUIGallery/ShowCases/Views/DataEntry/TreeSelectShowCase.axaml 中 "Show Tree Line" 示例。


8. 样式变体

TreeSelect 支持四种样式变体,通过 StyleVariant 属性设置:

<StackPanel Orientation="Vertical" Spacing="10">
    <atom:TreeSelect HorizontalAlignment="Stretch"
                     IsAllowClear="True"
                     PlaceholderText="Outline (default)"
                     StyleVariant="Outline" />
    <atom:TreeSelect HorizontalAlignment="Stretch"
                     IsAllowClear="True"
                     PlaceholderText="Filled"
                     StyleVariant="Filled" />
    <atom:TreeSelect HorizontalAlignment="Stretch"
                     IsAllowClear="True"
                     PlaceholderText="Borderless"
                     StyleVariant="Borderless" />
    <atom:TreeSelect HorizontalAlignment="Stretch"
                     IsAllowClear="True"
                     PlaceholderText="Underlined"
                     StyleVariant="Underlined" />
</StackPanel>

📖 参考:controlgallery/AtomUIGallery/ShowCases/Views/DataEntry/TreeSelectShowCase.axaml 中 "Variants" 示例。


9. 验证状态

通过 Status 属性设置 Error 或 Warning 状态,配合表单验证使用:

<StackPanel Orientation="Vertical" Spacing="10">
    <atom:TreeSelect HorizontalAlignment="Stretch"
                     IsAllowClear="True"
                     PlaceholderText="Error status"
                     Status="Error" />
    <atom:TreeSelect HorizontalAlignment="Stretch"
                     IsAllowClear="True"
                     PlaceholderText="Warning status"
                     Status="Warning" />
</StackPanel>

📖 参考:controlgallery/AtomUIGallery/ShowCases/Views/DataEntry/TreeSelectShowCase.axaml 中 "Status" 示例。


10. 前缀附加内容

通过 LeftAddOn 和 ContentLeftAddOn 属性为 TreeSelect 添加前缀内容:

<!-- LeftAddOn:独立的左侧装饰区域 -->
<atom:TreeSelect Name="LeftAddTreeSelect"
                 HorizontalAlignment="Stretch"
                 IsAllowClear="True"
                 PlaceholderText="Please select"
                 IsDefaultExpandAll="True"
                 LeftAddOn="Prefix"
                 IsFilterEnabled="True" />

<!-- ContentLeftAddOn:内容区域内的左侧前缀 -->
<atom:TreeSelect Name="ContentLeftAddTreeSelect"
                 HorizontalAlignment="Stretch"
                 IsAllowClear="True"
                 PlaceholderText="Please select"
                 IsDefaultExpandAll="True"
                 ContentLeftAddOn="Prefix"
                 IsFilterEnabled="True" />

📖 参考:controlgallery/AtomUIGallery/ShowCases/Views/DataEntry/TreeSelectShowCase.axaml 中 "Prefix and Suffix" 示例。


11. 最大选择数量

在多选/勾选模式下,通过 MaxCount 限制最大可选数量。达到上限后未选中节点自动禁用:

<!-- 多选模式 + MaxCount -->
<atom:TreeSelect Name="MaxSelectedTreeSelect"
                 HorizontalAlignment="Stretch"
                 IsDefaultExpandAll="True"
                 IsMultiple="True"
                 IsAllowClear="True"
                 IsFilterEnabled="True"
                 PlaceholderText="Please select"
                 IsShowMaxCountIndicator="True"
                 MaxCount="3" />

<!-- 勾选模式 + MaxCount -->
<atom:TreeSelect Name="MaxCheckedTreeSelect"
                 HorizontalAlignment="Stretch"
                 IsDefaultExpandAll="True"
                 IsMultiple="True"
                 IsTreeCheckable="True"
                 IsAllowClear="True"
                 IsFilterEnabled="True"
                 PlaceholderText="Please select"
                 IsShowMaxCountIndicator="True"
                 MaxCount="3" />

要点:

  • IsShowMaxCountIndicator="True" 在右侧显示 已选/最大 数量指示器
  • 当选中数量达到 MaxCount 时,TreeSelectTreeViewItem 会通过 IsMaxSelectReached 属性将未选中/未勾选的节点禁用

📖 参考:controlgallery/AtomUIGallery/ShowCases/Views/DataEntry/TreeSelectShowCase.axaml 中 "Max Count" 示例。


12. 获取选中值

单选模式

// 通过 SelectedItem 获取选中的节点
ITreeItemNode? selected = myTreeSelect.SelectedItem;
if (selected != null)
{
    Console.WriteLine($"Selected: {selected.Header} (Value: {selected.Value})");
}

多选/勾选模式

// 通过 SelectedItems 获取所有选中的节点
IList<ITreeItemNode>? selectedItems = myTreeSelect.SelectedItems;
if (selectedItems != null)
{
    foreach (var item in selectedItems)
    {
        Console.WriteLine($"Selected: {item.Header}");
    }
}

清空选中项

// 调用 Clear() 方法清空所有选中项
myTreeSelect.Clear();

常见组合模式

表单中使用 TreeSelect

<atom:FormItem Label="Department">
    <atom:TreeSelect IsAllowClear="True"
                     PlaceholderText="Select department"
                     HorizontalAlignment="Stretch" />
</atom:FormItem>

多选 + 搜索 + 最大数量限制

<atom:TreeSelect IsMultiple="True"
                 IsFilterEnabled="True"
                 IsAllowClear="True"
                 MaxCount="5"
                 IsShowMaxCountIndicator="True"
                 PlaceholderText="Select up to 5 items"
                 HorizontalAlignment="Stretch" />

勾选 + 仅展示叶子节点

<atom:TreeSelect IsTreeCheckable="True"
                 ShowCheckedStrategy="ShowChild"
                 IsAllowClear="True"
                 IsDefaultExpandAll="True"
                 PlaceholderText="Select leaf nodes"
                 HorizontalAlignment="Stretch" />

异步加载 + 搜索

<atom:TreeSelect IsFilterEnabled="True"
                 IsAllowClear="True"
                 DataLoader="{Binding MyDataLoader}"
                 PlaceholderText="Search and load"
                 HorizontalAlignment="Stretch" />