在项目中,时常会遇到存在上下级关系的数据。在呈现方面,按照传统方法,不得不组装TreeNode之后添加到TreeView 中,已实现树形数据的显示。如果项目中需要多处使用树,毫无疑问这将存在巨大的代码冗余,会有无数针对不同实体组件TreeNode的代码出现,整体风格糟糕至极。

  在近期的项目中,很多地方拥有这样的上下级关系,如下图所示,可以清楚的看出它们直接的关系

  在数据的查询上,一般对于Oracle不太熟悉的人,可能就会采用 in或者exist关键字来进行筛选, 实际上Oracle有已经有递归查询的语法存在,对于Oracle不太熟悉的看官,可以百度一下。

这里列出了示例:

select t.project_id,t.project_name,t.p_project_id,t.p_project_name,t.category from sys_project_info s start with s.category in (10,11,21) connect by prior s.project_id=s.p_project_id and s.project_name = s.p_project_name;

  

  到这里数据的提取部分就已经完成,剩下的就是树形数据的组建过程,也就是数据的呈现。归根结底还是递归,在这里只是对递归过程进行了封装,可以直接移植到WPF或者Silverlight项目中,代码如下:

 using Microsoft.Practices.Prism.ViewModel;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Runtime.Serialization;
using System.Text; namespace SysManager.Utility
{
public class TreeNode<T> : NotificationObject where T : BaseEntity
{
private T _parentNode;
private T _currentNode;
private bool _isChecked;
private bool _canChecked; /// <summary>
/// 父节点
/// </summary>
public dynamic Key { get; set; } /// <summary>
/// 子节点
/// </summary>
public ObservableCollection<TreeNode<T>> ChildrenNodes { get; set; } /// <summary>
/// 是否允许被选中
/// </summary>
public bool CanChecked
{
get { return _canChecked; }
set
{
if (_canChecked == value)
return;
_canChecked = value;
RaisePropertyChanged("CanChecked");
}
} /// <summary>
/// 是否处于被选中状态
/// </summary>
public bool IsChecked
{
get { return _isChecked; }
set
{
if (_isChecked == value)
return;
_isChecked = value;
RaisePropertyChanged("IsChecked");
}
}
/// <summary>
/// 当前选中节点
/// </summary>
public T CurrentNode
{
get { return _currentNode; }
set
{
if (_currentNode == value)
return;
_currentNode = value;
RaisePropertyChanged("CurrentNode");
}
}
/// <summary>
/// 当前节点的父级节点
/// </summary>
public T ParentNode
{
get { return _parentNode; }
set
{
if (_parentNode == value)
return;
_parentNode = value;
RaisePropertyChanged("ParentNode");
}
} public TreeNode()
{
this.CanChecked = true;
} static TreeNode<T> staticNode; /// <summary>
/// 将数据组织成一个拥有上下级管理的树形结构数据集合
/// </summary>
/// <typeparam name="TKey">主键的数据类型</typeparam>
/// <param name="nodeSource">执行过GroupBy语句的数据源</param>
/// <param name="resultTreeNode">结果数据</param>
/// <param name="keyName">子节点标识字段名称</param>
/// <param name="parentKeyName">父节点标识字段名称</param>
/// <param name="orderByKeys"></param>
/// <returns>已生成的树形结构实体</returns>
public TreeNode<T> GenerateTreeNodes<TKey>(IEnumerable<IGrouping<TKey, T>> nodeSource, TreeNode<T> resultTreeNode, string keyName, string parentKeyName)
{
var orderedSource = nodeSource.OrderBy(groupList => groupList.Key);
foreach (IGrouping<TKey, T> item in orderedSource)
{
var listChildrenNode = new ObservableCollection<TreeNode<T>>();
object propertyParentValue = null; foreach (var child in item)
{
//get children id
object propertyValue = GetCurrentItemPropertyValue(keyName, child);
//get parent id
if (propertyParentValue == null)
propertyParentValue = GetCurrentItemPropertyValue(parentKeyName, child); if (propertyValue != propertyParentValue)
{
T parentNodeInstance = null;
if (propertyParentValue != null)
{
var nodeParent = nodeSource.Where(x => x.Key.ToString() == propertyParentValue.ToString()).FirstOrDefault();
if (nodeParent != null)
parentNodeInstance = nodeParent.FirstOrDefault();
}
var node = new TreeNode<T>() { CurrentNode = child, Key = propertyValue, ChildrenNodes = new ObservableCollection<TreeNode<T>>(), ParentNode = parentNodeInstance };
listChildrenNode.Add(node);
} } TreeNode<T> parentNode = null;
foreach (var root in listChildrenNode)
{
staticNode = null;
parentNode = FindParentNode(resultTreeNode, item.Key);
if (parentNode != null)
break;
}
if (parentNode != null)
{
parentNode.ChildrenNodes = listChildrenNode;
}
else
listChildrenNode.ToList().ForEach(childNode => resultTreeNode.ChildrenNodes.Add(childNode)); }
return resultTreeNode;
} /// <summary>
/// 将一个拥有上下级关系的Tree转换为列表
/// </summary>
public IEnumerable TreeNode2LinkedList { get; private set; }
/// <summary>
/// 将treenode转换为列表
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="originalSource"></param>
public void TreeNodeToLinkedList(TreeNode<T> originalSource)
{
if (originalSource != null && originalSource.ChildrenNodes != null)
{
if (originalSource.CurrentNode != null)
{
if (TreeNode2LinkedList == null)
TreeNode2LinkedList = new List<T>();
(TreeNode2LinkedList as List<T>).Add(originalSource.CurrentNode);
}
foreach (var item in originalSource.ChildrenNodes)
{
TreeNodeToLinkedList(item);
}
}
} private static object GetCurrentItemPropertyValue(string keyName, T child)
{
var property = child.GetType().GetProperties().Where(prop => prop.Name == keyName).FirstOrDefault();
object propertyValue = null;
if (property != null)
propertyValue = property.GetValue(child, null);
return propertyValue;
} /// <summary>
/// 寻找当前节点的父级节点
/// </summary>
/// <param name="rootNode">当前节点</param>
/// <param name="key">节点的Key</param>
/// <returns>父级节点</returns>
private TreeNode<T> FindParentNode(TreeNode<T> rootNode, dynamic key)
{ if (rootNode.ChildrenNodes == null)
return rootNode;
foreach (var children in rootNode.ChildrenNodes)
{
if (children.Key == key)
{
staticNode = children;
break;
}
else
if (staticNode == null)
FindParentNode(children, key);
}
if (rootNode.Key != null && (int)rootNode.Key == key)
return rootNode; return staticNode; }
}
}

  

//调用方法
var treeNode = new TreeNode<SysProjectInfoEntity>();
treeNode.GenerateTreeNodes<decimal?>(result.OfType<SysProjectInfoEntity>().GroupBy(proj => proj.ParentProjectId), treeNode, "ProjectId", "ParentProjectId");

wpf数据自动树结构的更多相关文章

  1. 利用在线工具根据JSon数据自动生成对应的Java实体类

    如果你希望根据JSon数据自动生成对应的Java实体类,并且希望能进行变量的重命名,那么“JSON To Java”一定适合你.(下面的地址需要FQ) https://jsontojava.appsp ...

  2. struts中的请求数据自动封装

    Struts 2框架会将表单的参数以同名的方式设置给对应Action的属性中.该工作主要是由Parameters拦截器做的.而该拦截器中已经自动的实现了String到基本数据类型之间的转换工作.在st ...

  3. 只用css实现“每列四行,加载完一列后数据自动填充到下一列”的效果

    只用css实现“每列四行,加载完一列后数据自动填充到下一列”的效果.这个题目用图表示如下: 如果将题目换成“只用css实现每行四列,加载完一行后数据自动填充到下一行”,那这个问题就简单多了,相信大家都 ...

  4. jQuery插件:Ajax将Json数据自动绑定到Form表单

    jQuery注册方法的两种常用方式: //jQuery静态方法注册 //调用方法$.a1() $.extend({ a1: function () { console.log("a1&quo ...

  5. 在javaScript中把非数值类型的数据自动转换为数值类型的两种方式

    一.使用Number()函数. 二.使用parseInt()/parseFloat()函数. 详情: 一.使用Number()函数将非数值类型的数据自动的转化为数组类型 Number()函数可以将任何 ...

  6. ibatis实战之插入数据(自动生成主键)

    ibatis实战之插入数据(自动生成主键) --------- 如果你将数据库设计为使用自动生成的主键,就可以使用ibatis的<selectKey>元素(该元素是<insert&g ...

  7. Struts2(接受表单参数)请求数据自动封装和数据类型转换

    Struts2请求数据自动封装: (1)实现原理:参数拦截器 (2)方式1:jsp表单数据填充到action中的属性:        普通的成员变量,必须给set,get可以不给的.    注意点,A ...

  8. ArcGIS案例学习笔记-CAD数据自动拓扑检查

    ArcGIS案例学习笔记-CAD数据自动拓扑检查 联系方式:谢老师,135-4855-4328,xiexiaokui#qq.com 功能:针对CAD数据,自动进行拓扑检查 优点:类别:地理建模项目实例 ...

  9. wpf数据验证实例及常用方法小结

    虽然标题是wpf数据验证,但并不是对IDataErrorInfo.ValidationRule.属性中throw Exception这几种验证方式的介绍: 之前做项目时(例如员工工资管理),根据员工编 ...

随机推荐

  1. Maven : 将Jar安装到本地仓库和Jar上传到私服 转

    http://blog.csdn.net/we_shell/article/details/49819221 Jar的maven配置 <dependency><groupId> ...

  2. web前后台数据交互的四种方式(转)

    1.利用cookie对象  Cookie是服务器保存在客户端中的一小段数据信息.使用Cookie有一个前提,就是客户端浏览器允许使用Cookie并对此做出相应的设置.一般不赞成使用Cookie. (1 ...

  3. ASP.NET MVC- VIEW Overview Part 1

    The purpose of this tutorial is to  provide you with a brief introduction to ASP.NET MVC views, view ...

  4. svn 上传 过滤

    代码上传过程中发现.so文件不能上传,查了一下,发现是svn服务器要设置上传过滤:很多文件,会被过滤掉,不能正常上传.设置如下: 通过终端打开配置文件: open ~/.subversion/conf ...

  5. 【web开发学习笔记】ibatis学习总结

    ibatis学习总结 ibatis数据库配置文件 <?xml version="1.0" encoding="UTF-8" ?> <!DOCT ...

  6. Apache Solr配置

    Solr配置 Solr的主要功能是全文检索,该功能分为两个过程:创建索引和对索引进行搜索: 在创建索引之前,需要重点关注两个配置文件:SOLR_HOME/collection1/conf/schema ...

  7. WCF探索之旅(一)——入门

    背景 对于.NET程序员来说,假设你不知道WCF,那仅仅能说明一点:你还是个菜鸟. 曾经也用.NET做过几个系统,尤其做后面的系统的时候,心里就有点沾沾自喜了! 想着,.NET也就这点东西,我如今也能 ...

  8. DevExpress的GridView设置特定行的样式

    GridView控件绑定事件: gridView_SampleData.CustomDrawCell += gridView_SampleData_CustomDrawCell; 根据自定义逻辑来改变 ...

  9. thinking in java 读书笔记 --- overriding private method

    一个对象可以被用作它自身的类型或者是它的基类类型.当用作它的基类类型时叫做upcasting,如下所示 BaseClass ref = new DerivedClass()  //upcasting ...

  10. ASP.NET+ashx+jQuery动态添加删除表格

    aspx: <script src="../script/jquery-1.4.4.min.js" type="text/javascript" lang ...