zoukankan      html  css  js  c++  java
  • 扁平状数据链接成树状结构的通用方法

    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#
  • 相关阅读:
    现代C语言程序设计之数据存储
    Linux系统运维与架构设计之文件管理
    Linux系统运维与架构设计之系统基本使用
    Linux系统运维与架构设计之搭建运维环境
    Linux系统运维与架构设计之Linux概述
    Linux系统运维与架构设计技术栈
    架构师成长之道-C语言基础之C语言概述
    K3/Cloud树形单据体的rowId赋值
    K3违反内码唯一键约束
    K3修改字段名
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2958390.html
Copyright © 2011-2022 走看看