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#
  • 相关阅读:
    Notes about "Exploring Expect"
    Reuse Sonar Checkstyle Violation Report for Custom Data Analysis
    Eclipse带参数调试的方法
    MIT Scheme Development on Ubuntu
    Manage Historical Snapshots in Sonarqube
    U盘自动弹出脚本
    hg的常用配置
    Java程序员的推荐阅读书籍
    使用shared memory 计算矩阵乘法 (其实并没有加速多少)
    CUDA 笔记
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2958390.html
Copyright © 2011-2022 走看看