在项目中,时常会遇到存在上下级关系的数据。在呈现方面,按照传统方法,不得不组装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. sql server2008报“评估已过期....."

    开始-->所有程序-->Microsoft SQL Server 2008-->配置工具-->SQL Server 安装中心-->维护-->版本升级,接着按照提示一 ...

  2. 编码实战Web端联系人的增删改查

    首先画出分析图 实现效果如图 项目下的包如图: 实体包 package com.contactSystem.entiey; public class Contact { private String ...

  3. 通过rest接口获取自增id (twitter snowflake算法)

    1.  算法介绍 参考 http://www.lanindex.com/twitter-snowflake%EF%BC%8C64%E4%BD%8D%E8%87%AA%E5%A2%9Eid%E7%AE% ...

  4. Uncaught TypeError: Cannot read property 'post' of undefined

  5. Request的getParameter和getAttribute方法的区别

    下面整理一下getParameter和getAttribute的区别和各自的使用范围.      (1)HttpServletRequest类有setAttribute()方法,而没有setParam ...

  6. 标准差(standard deviation)和标准误差(standard error)你能解释清楚吗?

    by:ysuncn(欢迎转载,请注明原创信息) 什么是标准差(standard deviation)呢?依据国际标准化组织(ISO)的定义:标准差σ是方差σ2的正平方根:而方差是随机变量期望的二次偏差 ...

  7. c语言中的 %u 什么意思啊?

    %d 有符号10进制整数 %i 有符号10进制整数 %o 无符号8进制整数 %u 无符号10进制整数 %x 无符号的16进制数字,并以小写abcdef表示%X 无符号的16进制数字,并以大写ABCDE ...

  8. App升级时数据库的迁移更新

    前一段时间在进行App升级的时候,由于一开始版本初期没有考虑完善,导致走了很多弯路,后来经过自己的一些思考,总结出了一些在app升级的时候,数据库内文件同步保持更新的经验,希望能给大家带来帮助. 总体 ...

  9. MyTask4

    最近稍微做了点修改,把几处bug修复了下,另外新增了授权码功能和数据缓冲功能 先看看效果图 1. 如果要把软件做的高大上一些,你可以加一个授权验证,授权码以字符串形式存放在程序里面,当然你也可以另外开 ...

  10. Java 文件下载

    public HttpServletResponse download(String path, HttpServletResponse response) { try { // path是指欲下载的 ...