在项目中,时常会遇到存在上下级关系的数据。在呈现方面,按照传统方法,不得不组装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. Coding girl一个老程序员谈到的一个女程序员的故事

    因为有人说我给一个女程序员的建议不靠谱,我不服,因为我的工作经历中的一些女程序员都很不错,比那些男程序员都强,所以,我在新浪微博和twitter上征集女程序员的故事和想法,这两天来,我收到了好几封邮件 ...

  2. [置顶] 如何访问web文件夹之外的文件

        在编写项目时,遇到一个如何访问web文件夹之外的文件的问题.因为我要制作一个浏览图片和pdf文件的一个简单网站.但问题是图片的文件夹和pdf文件的文件夹都是其他程序生成的,自然也就是不是网站w ...

  3. (3/18)重学Standford_iOS7开发_Objective-C_课程笔记

    第三课: 本节课主要是游戏实现的demo,因此我将把课程中简单的几个编程技巧提取出来,重点介绍如何自己实现作业中的要求. 纸牌游戏实现: ①游戏的进行是模型的一部分(理解什么是模型:Model = W ...

  4. postgresql9.5 run 文件linux安装后配置成开机服务

    网上出现的比较多安装方法要么是源码安装,要么是yum安装,我发觉都要配置很多属性,比较麻烦,所以现在我在centos7长用 run文件来安装 http://get.enterprisedb.com/p ...

  5. 让Tomcat支持中文路径名和中文文件名

    http://hdwangyi.iteye.com/blog/107709 Tomcat是Java开发者使用得较多的一个Web服务器,因为它占用资源小,运行速度快等特点,深受Java Web程序员的喜 ...

  6. 自主创建tcpdump/wireshark pcap文件

      pcap文件格式是bpf保存原始数据包的格式,很多软件都在使用,比如tcpdump.wireshark等等,了解pcap格式可以加深对原始数据包的了解,自己也可以手工构造任意的数据包进行测试. p ...

  7. python学习笔记--Django入门一 网页显示时间

    我的笔记是学习http://djangobook.py3k.cn/ 课程时做的,这个上边的文章讲的确实是非常的详细,非常感谢你们提供的知识. 上一篇随笔中已经配置好了Django环境,现在继续跟随ht ...

  8. Linux平台的boost安装全解

    @import url(http://i.cnblogs.com/Load.ashx?type=style&file=SyntaxHighlighter.css); @import url(/ ...

  9. Class Fxp\Composer\AssetPlugin\Repository\NpmRepository does not exist

    使用 composer 安装 laravel 时报错, 如下: [ReflectionException] Class Fxp\Composer\AssetPlugin\Repository\NpmR ...

  10. linux vncserver配置

    需要使用Linux的远程桌面服务,xmanager之前用过,感觉一般,这次尝试下vnc 我的操作系统是centos7 一服务端 安装VNCServer #yum -y install vnc *vnc ...