好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

扁平状数据链接成树状结构的通用方法

扁平状数据链接成树状结构的通用方法

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://www.cnblogs.com/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于扁平状数据链接成树状结构的通用方法的详细内容...

  阅读:65次