扁平状数据链接成树状结构的通用方法
C# 将扁平状数据链接成树状结构的通用方法
在项目中经常会遇到从数据库查询数据绑定到TreeVIew上,这时我们需要将查询出来的数据转换成树形结构数据,每次写觉得工作会很重复,所以写了一个通用的转换类。
第一步,我们需要建一个基类,这个基类的意义主要是扩展数据库实体类做连接用,用于确定树形结构中节点与子项的关系,
其中Parent为当前节点的父节点,Children为当前节点的子节点,IsLinked是判断当前节点是否已连接,用于防止数据中有循环依赖导致创建树的时候形成死循环。
TreeModel基类
public class TreeBase<T>
{
private bool isLinked = false ;
/// <summary>
/// 是否已创建连接
/// </summary>
public bool IsLinked
{
get { return isLinked; }
set { isLinked = value; }
}
/// <summary>
/// 父节点
/// </summary>
public T Parent { get ; set ; }
/// <summary>
/// 子节点
/// </summary>
public ObservableCollection<T> Children { get ; set ; }
}
第二步,我们需要创建一个连接方法,将输入的扁平状数据转换为树状结构,我希望在使用的时候可以自己指定实体的哪个属性为ID,哪个为父ID
,这里我们使用了Expression,这样就可以使用linq表达式去指定属性了,剩下的就是利用反射获取实体的值与递归连接了,这样一个简单的通用创建树的方法就有了。
public class TreeHelper
{
/// <summary>
/// 创建树
/// </summary>
/// <typeparam name="T"> 实体类型 </typeparam>
/// <param name="root"> 根节点 </param>
/// <param name="list"> 所有数据 </param>
/// <param name="idProperty"> 节点唯一标识属性表达式 </param>
/// <param name="parentIdProperty"> 父节点属性表达式 </param>
public static void CreateTree<T>(T root, IList<T> list, string idPropertyName, string parentIdPropertyName) where T : TreeBase<T>
{
root.Children = new ObservableCollection<T> ();
list.Where(e => ( string )GetPropertyValue(e, parentIdPropertyName) == ( string )GetPropertyValue(root, idPropertyName) && !e.IsLinked).ToList().ForEach(e => { root.Children.Add(e); e.IsLinked = true ; });
foreach ( var leaf in root.Children)
{
leaf.Parent = root;
CreateTree <T> (leaf, list, idPropertyName, parentIdPropertyName);
}
}
/// <summary>
/// 创建多个根节点的树
/// </summary>
/// <typeparam name="T"> 实体类型 </typeparam>
/// <param name="root"> 根节点 </param>
/// <param name="list"> 所有数据 </param>
/// <param name="idProperty"> 节点唯一标识属性表达式 </param>
/// <param name="parentIdProperty"> 父节点属性表达式 </param>
public static ObservableCollection<T> CreateTree<T>(IList<T> list, Expression<Func<T, object >> idProperty, Expression<Func<T, object >> parentIdProperty) where T : TreeBase<T>
{
// 查找父节点不存在的leaf,作伪根节点
var roots = new ObservableCollection<T> ();
var idPropertyName = GetMemberName(idProperty);
var parentIdPropertyName = GetMemberName(parentIdProperty);
list.Where(e => list.Count(item =>
( string )GetPropertyValue(item, idPropertyName) == ( string )GetPropertyValue(e, parentIdPropertyName)) == 0 ).ToList().ForEach(e => roots.Add(e));
foreach ( var root in roots)
{
CreateTree <T> (root, list, idPropertyName, parentIdPropertyName);
}
return roots;
}
private static object GetPropertyValue<T>(T t, string propertyName)
{
return t.GetType().GetProperty(propertyName).GetValue(t, null );
}
private static string GetMemberName<T, TMember>(Expression<Func<T, TMember>> propertySelector)
{
var propertyExp = propertySelector.Body as MemberExpression;
if (propertyExp == null )
{
throw new ArgumentException( " 不合理的表达式! " );
}
return propertyExp.Member.Name;
}
}
使用示例:
先声明一个绑定实体,继承自TreeBase
public class Item : TreeBase<Item>
{
public string Id{get;set;}
public string ParentID{get;set;}
public string DisplayText{get;set;}
}
创建测试数据
IList<Item> data = new List<Item> ();
var group1= new Item(){ Id = Guid.NewGuid().ToString(), DisplayText= " Root " };
var item1 = new Item { Id = Guid.NewGuid().ToString(), ParentId = group1.Id, DisplayText = " Leaf1 " };
var item2 = new Item { Id = Guid.NewGuid().ToString(), ParentId = group1.Id, DisplayText = " Leaf2 " };
var item3 = new Item { Id = Guid.NewGuid().ToString(), ParentId = group1.Id, DisplayText = " Leaf3 " };
var item4 = new Item() { Id = Guid.NewGuid().ToString(), ParentId = item3.Id, DisplayText = " Leaf3:Leaf1 " };
var item5 = new Item() { Id = Guid.NewGuid().ToString(), ParentId = item3.Id, DisplayText = " Leaf3:Leaf2 " };
var item6 = new Item() { Id = Guid.NewGuid().ToString(), ParentId = item3.Id, DisplayText = " Leaf3:Leaf3 " };
data.Add(group1);
data.Add(item1);
data.Add(item2);
data.Add(item3);
data.Add(item4);
data.Add(item5);
data.Add(item6);
界面模板绑定
< TreeView Height ="245" HorizontalAlignment ="Left" Margin ="46,35,0,0" Name ="treeView1" VerticalAlignment ="Top" Width ="156" >
< TreeView.ItemTemplate >
< HierarchicalDataTemplate ItemsSource =" {Binding Children} " >
< TextBlock Text =" {Binding DisplayText} " ></ TextBlock >
</ HierarchicalDataTemplate >
</ TreeView.ItemTemplate >
</ TreeView >
后台数据绑定
treeView1.ItemsSource = TreeHelper.CreateTree<Item>(data, item => item.Id, item => item.ParentId);
以后绑定树形数据是不是很简单呢?
这种方法不适应主键为Guid的数据类型
因为以下代码无法获取Guid类型的名称,欢迎各位大叔,大婶,大神们指点
private static string GetMemberName<T, TMember>(Expression<Func<T, TMember>> propertySelector)
{
var propertyExp = propertySelector.Body as MemberExpression;
if (propertyExp == null )
{
throw new ArgumentException( " 不合理的表达式! " );
}
return propertyExp.Member.Name;
}
分类: C#
作者: Leo_wl
出处: http://HdhCmsTestcnblogs测试数据/Leo_wl/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
版权信息查看更多关于扁平状数据链接成树状结构的通用方法的详细内容...
声明:本文来自网络,不代表【好得很程序员自学网】立场,转载请注明出处:http://www.haodehen.cn/did46629