# 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: 完善文档和示例