# TreeListView **Repository Path**: linxiaoming123/TreeListView ## Basic Information - **Project Name**: TreeListView - **Description**: 一个提供树状表格功能的WPF控件 - **Primary Language**: C# - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-06-06 - **Last Updated**: 2026-06-06 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # TreeViewList 控件文档 ## 1. 概述 TreeViewList 是一个功能强大的树状表格控件,支持: - 虚拟滚动,高效处理大量数据 - 多种数据加载模式(一次性加载、动态按需加载、范围加载) - MVVM 模式支持 - 可自定义列和模板 - 节点选择和展开/折叠 - 详细信息面板 ## 2. 基础使用方法 ### 2.1 在 XAML 中使用 ```xml ``` ### 2.2 在代码中使用 ```csharp // 创建控件实例 var treeViewList = new TreeListViewControl(); // 设置数据源 treeViewList.ItemsSource = root.Children; // 设置列 treeViewList.Columns = new GridViewColumnCollection() { new GridViewColumn() { Header = "名称", Width = 100, DisplayMemberBinding = new Binding("Name") }, new GridViewColumn() { Header = "职位", Width = 100, DisplayMemberBinding = new Binding("JobTitle") } }; // 设置选中项事件 treeViewList.SelectedItemChanged += (sender, e) => { // 处理选中项变化 }; ``` ## 3. TreeListViewItemBase 的使用 ### 3.1 继承 TreeListViewItemBase ```csharp public class MyTreeItem : TreeListViewItemBase { [ObservableProperty] private string _name; [ObservableProperty] private string _jobTitle; [ObservableProperty] private int _age; public MyTreeItem(string name, string jobTitle, int age) { _name = name; _jobTitle = jobTitle; _age = age; this.DisplayName = name; // 设置显示名称 } } ``` ### 3.2 关键属性和方法 | 属性/方法 | 描述 | |---------|------| | `Children` | 子节点集合 | | `Parent` | 父节点 | | `IsExpanded` | 是否展开 | | `IsSelected` | 是否选中 | | `IsLoading` | 是否正在加载子节点 | | `HasLoadedChildren` | 是否已加载过子节点 | | `TotalChildCount` | 子节点总数(用于虚拟滚动) | | `AddRange` | 批量添加子节点 | | `GetAllChildren` | 获取所有子节点 | | `Ancestors` | 获取所有祖先节点 | | `Siblings` | 获取所有兄弟节点 | ## 4. 动态加载数据接口的使用 ### 4.1 一次性加载模式 ```csharp // 创建根节点 var root = new MyTreeItem("Root", "Root", 0); // 创建子节点 var child1 = new MyTreeItem("Child1", "Child", 1); var child2 = new MyTreeItem("Child2", "Child", 2); // 添加子节点 root.Children.Add(child1); root.Children.Add(child2); // 设置到控件 treeViewListControl.DataLoadMode = TreeDataLoadMode.OneTime; treeViewListControl.ItemsSource = root.Children; ``` ### 4.2 动态按需加载模式 ```csharp // 创建根节点 var root = new MyTreeItem("Root", "Root", 0) { HasChildren = true }; var rootNodes = new List { root }; // 创建数据提供者 var dataProvider = new DynamicOnDemandTreeDataProvider( rootNodes, GetChildNodesAsync, // 异步获取子节点的方法 HasChildNodesAsync); // 异步检查是否有子节点的方法 // 设置到控件 treeViewListControl.DataProvider = dataProvider; treeViewListControl.DataLoadMode = TreeDataLoadMode.DynamicOnDemand; treeViewListControl.ItemsSource = rootNodes; // 异步获取子节点的实现 private async Task> GetChildNodesAsync(MyTreeItem parentNode) { // 模拟异步加载 await Task.Delay(100); // 生成子节点 var children = new List(); for (int i = 0; i < 10; i++) { var child = new MyTreeItem( $"Node_{parentNode.Level + 1}_{i}", $"Level{parentNode.Level + 1}", 25) { HasChildren = parentNode.Level < 3 // 只有前三层有子节点 }; children.Add(child); } return children; } // 异步检查是否有子节点的实现 private async Task HasChildNodesAsync(MyTreeItem parentNode) { // 模拟异步检查 await Task.Delay(50); // 只有前三层有子节点 return parentNode.Level < 3; } ``` ### 4.3 范围加载模式 ```csharp // 创建根节点 var root = new MyTreeItem("Root", "Root", 0) { HasChildren = true }; var rootNodes = new List { root }; // 创建范围加载数据提供者 var dataProvider = new RangedTreeDataProvider( rootNodes, GetChildNodeCountAsync, // 获取子节点总数的方法 GetChildNodesRangeAsync, // 获取指定范围子节点的方法 HasChildNodesAsync); // 检查是否有子节点的方法 // 创建虚拟化集合 var virtualizedCollection = new VirtualizedTreeViewCollection( rootNodes, GetChildNodesAsync, // 兼容原有逻辑 GetChildNodeCountAsync, // 获取子节点总数的方法 HasChildNodesAsync); // 检查是否有子节点的方法 // 设置到控件 treeViewListControl.DataProvider = dataProvider; treeViewListControl.DataLoadMode = TreeDataLoadMode.DynamicOnDemand; treeViewListControl.VirtualizedCollection = virtualizedCollection; // 获取子节点总数的实现 private async Task GetChildNodeCountAsync(MyTreeItem parentNode) { await Task.Delay(50); return 100; // 返回子节点总数 } // 获取指定范围子节点的实现 private async Task> GetChildNodesRangeAsync(MyTreeItem parentNode, int startIndex, int count) { await Task.Delay(100); var children = new List(); for (int i = startIndex; i < startIndex + count; i++) { var child = new MyTreeItem( $"Node_{parentNode.Level + 1}_{i}", $"Level{parentNode.Level + 1}", 25) { HasChildren = parentNode.Level < 3 }; children.Add(child); } return children; } ``` ## 5. 高级功能 ### 5.1 虚拟滚动 ```csharp // 创建虚拟化集合 var virtualizedCollection = new VirtualizedTreeViewCollection( rootNodes, GetChildNodesAsync, GetChildCountAsync, HasChildNodesAsync); // 设置到控件 treeViewListControl.VirtualizedCollection = virtualizedCollection; ``` ## 6. 数据绑定示例 ```csharp // ViewModel public partial class TreeViewModel : ObservableObject { [ObservableProperty] private MyTreeItem _root; [ObservableProperty] private MyTreeItem _selectedItem; public TreeViewModel() { // 初始化数据 Root = new MyTreeItem("Root", "Root", 0); var child1 = new MyTreeItem("Child1", "Child", 1); var child2 = new MyTreeItem("Child2", "Child", 2); Root.Children.Add(child1); Root.Children.Add(child2); } } ``` ```xaml ``` ## 7. 常见问题 ### 7.1 如何处理大量数据 - 使用 `TreeDataLoadMode.DynamicOnDemand` 或范围加载模式 - 使用 `VirtualizedTreeViewCollection` 实现虚拟滚动 - 设置 `TotalChildCount` 属性以获得正确的滚动条大小 ### 7.2 如何自定义节点样式 - 使用 `ItemDetailTemplate` 自定义节点详细信息面板 - 使用 `ItemDetailTemplateSelector` 根据条件选择不同的模板 - 自定义 `GridViewColumn` 的 `CellTemplate` 自定义列样式 ### 7.3 如何手动展开/折叠节点 ```csharp // 展开节点 item.IsExpanded = true; // 折叠节点 item.IsExpanded = false; // 展开所有节点 foreach (var child in item.Children) { child.IsExpanded = true; } ``` ## 8. 性能优化建议 1. 使用批量添加方法 `AddRange` 替代逐个添加子节点 2. 对于大量数据,使用动态加载或范围加载模式 3. 合理设置 `TotalChildCount`,避免不必要的计算 4. 避免在 UI 线程中执行耗时的操作 5. 使用虚拟滚动减少内存占用 6. 合理设置缓冲大小,平衡加载次数和内存占用 ## 9. 版本历史 - 1.0: 初始版本,支持基本的树状表格功能 - 1.1: 添加动态按需加载模式 - 1.2: 添加虚拟滚动支持 - 1.3: 添加范围加载模式 - 1.4: 优化选中节点定位逻辑 - 1.5: 完善文档和示例