.NET C# 树遍历、查询、拷贝与可视化
树结构组件,支持查询、遍历、拷贝、可视树过滤(不改变树结构,只过滤显示效果)
1 组件安装
1.1 NuGet包管理器安装:
1.2 控制台安装:
NuGet\Install-Package Zhy.Components.Tree -Version 1.0.3
NuGet\Install-Package Zhy.Components.Tree.Extension -Version 1.0.3
2 接口
1.1 ITree<TTreeNode>
public class TestTree : ITree<TestTree>
{
public string Id { get; set; }
public string Name { get; set; }
public TestTree Parent { get; set; }
public List<TestTree> Children { get; set; }
public TestTree(string id, string name, TestTree parent, List<TestTree> children)
{
Id = id;
Name = name;
Parent = parent;
Children = children;
}
public TestTree Clone()
{
var childListClone = new List<TestTree>();
if (Children != null)
{
foreach (var child in Children)
{
var childClone = child.Clone();
childClone.Parent = this;
childListClone.Add(childClone);
}
}
return new TestTree(Id, Name, null, childListClone);
}
}
1.2 ITree<TKey, TTreeNode>
public class TestTree2 : ITree<string, TestTree2>
{
public string Id { get; set; }
public string Name { get; set; }
public string Key { get; set; }
public string PKey { get => Parent?.Key; }
public TestTree2 Parent { get; set; }
public List<TestTree2> Children { get; set; }
public TestTree2 this[string key]
{
get => Children.First(x => x.Key == key);
set
{
TestTree2 node = Children.First(x => x.Key == key);
int idx = Children.IndexOf(node);
Children[idx] = value;
}
}
public TestTree2(string id, string name, string key, TestTree2 parent, List<TestTree2> children)
{
Id = id;
Name = name;
Key = key;
Parent = parent;
Children = children;
}
public TestTree2 Clone()
{
var childListClone = new List<TestTree2>();
if (Children != null)
{
foreach (var child in Children)
{
var childClone = child.Clone();
childClone.Parent = this;
childListClone.Add(childClone);
}
}
return new TestTree2(Id, Name, Key, null, childListClone);
}
}
1.3 IObservableTree<TTreeNode>
public class TestTree : ITree<TestTree>
{
public string Id { get; set; }
public string Name { get; set; }
public TestTree Parent { get; set; }
public List<TestTree> Children { get; set; }
public TestTree(string id, string name, TestTree parent, List<TestTree> children)
{
Id = id;
Name = name;
Parent = parent;
Children = children;
}
public TestTree Clone()
{
var childListClone = new List<TestTree>();
if (Children != null)
{
foreach (var child in Children)
{
var childClone = child.Clone();
childClone.Parent = this;
childListClone.Add(childClone);
}
}
return new TestTree(Id, Name, null, childListClone);
}
}
1.4 IObservableTree<TKey, TTreeNode>
public class TestTree2 : ITree<string, TestTree2>
{
public string Id { get; set; }
public string Name { get; set; }
public string Key { get; set; }
public string PKey { get => Parent?.Key; }
public TestTree2 Parent { get; set; }
public List<TestTree2> Children { get; set; }
public TestTree2 this[string key]
{
get => Children.First(x => x.Key == key);
set
{
TestTree2 node = Children.First(x => x.Key == key);
int idx = Children.IndexOf(node);
Children[idx] = value;
}
}
public TestTree2(string id, string name, string key, TestTree2 parent, List<TestTree2> children)
{
Id = id;
Name = name;
Key = key;
Parent = parent;
Children = children;
}
public TestTree2 Clone()
{
var childListClone = new List<TestTree2>();
if (Children != null)
{
foreach (var child in Children)
{
var childClone = child.Clone();
childClone.Parent = this;
childListClone.Add(childClone);
}
}
return new TestTree2(Id, Name, Key, null, childListClone);
}
}
3 方法
Clone()
深拷贝方法,继承接口时实现。
TestTree testTree = new TestTree("0", "root", null, new List<TestTree>());
TestTree testTreeClone = testTree.Clone();
Search(Func<TTreeNode, bool> expression, bool isClone = false)
树查询方法。
expression: 委托,参数为树节点,返回值为True/False,表示节点是否符合查询规则;
isClone: 是否克隆新的对象,True - 在新的树上进行查询及修改,并返回新的树,False - 在原始树上进行查询及修改;
TestTree searchResult = testTree.Search(node => node.Name.StartsWith("vect"), true);
Traversal(Action<TTreeNode> expression)
树遍历方法。
expression: 委托,参数为树节点,遍历所有节点执行;
testTree.Traversal(node => Console.WriteLine(node.Name));
SafeTraversal(Action<TTreeNode> expression)
安全的树遍历,若遍历时对树节点结构进行修改时使用。
testTree.SafeTraversal(node =>
{
if (node.Name.EndsWith("1"))
{
node.Parent.Children.Remove(node);
}
});
Filter(Func<TTreeNode, bool> expression)
可视树过滤,不改变树结构,只影响树结构的可视化显示。
expression: 委托,参数为树节点,返回值为True/False,表示节点是否符合过滤规则;
testTree.Filter(n => n.Name.Contains(SearchText));
4 样例源码
TestTreeNode.cs
using CommunityToolkit.Mvvm.ComponentModel;
using System.Collections.ObjectModel;
namespace Zhy.Components.Tree.Test
{
public partial class TestTreeNode : ObservableObject, IObservableTree<TestTreeNode>
{
public TestTreeNode Parent { get; set; }
[ObservableProperty]
private string _name;
[ObservableProperty]
private ObservableCollection<TestTreeNode> _children;
//public ObservableCollection<TestTreeNode> Children
//{
// get => _children;
// set => SetProperty(ref _children, value);
//}
public TestTreeNode Clone()
{
TestTreeNode clone = new TestTreeNode
{
Name = _name,
};
if (Children?.Count > 0)
{
clone.Children = new ObservableCollection<TestTreeNode>();
foreach (var child in Children)
{
TestTreeNode subClone = child.Clone();
subClone.Parent = this;
clone.Children.Add(subClone);
}
}
return clone;
}
}
}
MainWindow.xaml
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition />
</Grid.RowDefinitions>
<DockPanel>
<Button
Command="{Binding SearchCommand}"
Content="查 询"
Cursor="Hand"
DockPanel.Dock="Right" />
<TextBox Text="{Binding SearchText}" />
</DockPanel>
<TreeView
Grid.Row="1"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
ItemsSource="{Binding TreeNodes}">
<TreeView.ItemContainerStyle>
<Style TargetType="TreeViewItem">
<Setter Property="IsExpanded" Value="True" />
</Style>
</TreeView.ItemContainerStyle>
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Children}">
<DockPanel x:Name="dp" Margin="0,2,0,2">
<TextBlock
VerticalAlignment="Center"
FontSize="14"
IsHitTestVisible="True"
Text="{Binding Name}" />
<TextBlock IsHitTestVisible="True" />
</DockPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Grid>
MainWindowViewModel.cs
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using System.Collections.ObjectModel;
using Zhy.Components.Tree.Extension;
namespace Zhy.Components.Tree.Test
{
public partial class MainWindowViewModel : ObservableObject
{
[ObservableProperty]
private ObservableCollection<TestTreeNode> _treeNodes;
[ObservableProperty]
private string _searchText;
public MainWindowViewModel()
{
_treeNodes = new ObservableCollection<TestTreeNode>
{
new TestTreeNode
{
Name = "资源目录",
Children = new ObservableCollection<TestTreeNode>
{
new TestTreeNode
{
Name = "矢量",
Children = new ObservableCollection<TestTreeNode>
{
new TestTreeNode
{
Name = "行政区划",
Children = new ObservableCollection<TestTreeNode>
{
new TestTreeNode
{
Name = "北京行政区划"
},
new TestTreeNode
{
Name = "天津行政区划"
},
new TestTreeNode
{
Name = "河北行政区划"
},
}
},
new TestTreeNode
{
Name = "管线",
}
}
},
new TestTreeNode
{
Name = "栅格",
Children = new ObservableCollection<TestTreeNode>
{
new TestTreeNode
{
Name = "正射影像",
Children = new ObservableCollection<TestTreeNode>
{
new TestTreeNode
{
Name = "北京遥感影像"
},
new TestTreeNode
{
Name = "天津遥感影像"
},
new TestTreeNode
{
Name = "河北遥感影像"
},
}
},
new TestTreeNode
{
Name = "DEM"
}
}
}
}
},
};
}
[RelayCommand]
private void Search()
{
foreach (var item in TreeNodes)
{
item.Filter(n => n.Name.Contains(SearchText));
}
}
}
}