在项目中,时常会遇到存在上下级关系的数据。在呈现方面,按照传统方法,不得不组装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 Server Reporting Services 自定义数据处理扩展DPE(Data Processing Extension)

    最近在做SSRS项目时,遇到这么一个情形:该项目有多个数据库,每个数据库都在不同的服务器,但每个数据库所拥有的数据库对象(table/view/SPs/functions)都是一模一样的,后来结合网络 ...

  2. Yii 将对象转化成数组

    将从数据库查找的对象,转换成数组,并且以设定属性键名称,用到ArrayHelper::toArray $posts = Post::find()->limit(10)->all(); $d ...

  3. MongoDB 复制集 (三) 内部数据同步

    一 数据同步        一个健康的secondary在运行时,会选择一个离自己最近的,数据比自己新的节点进行数据同步.选定节点后,它会从这个节点拉取oplog同步日志,具体流程是这样的:      ...

  4. How to delete a large number of data in SharePoint for List when refreshing data?

    Preface Recently thequestion was asked in the newsgroups about deleting a large number of itemsfrom ...

  5. android开发之bitmap使用

    bitmap是android中重要的图像处理工具类,通过bitmap可以对图像进行剪切.旋转.缩放等操作,同时还可以指定格式和压缩质量保存图像文件. 一.拿到一个Bitmap对象 查看源码我们知道,B ...

  6. android开发之merge结合include优化布局

    merge结合include优化android布局,效果不知道,个人感觉使用上也有很大的局限,不过还是了解一下,记录下来. 布局文件都要有根节点,但android中的布局嵌套过多会造成性能问题,于是在 ...

  7. 在iis中mantisbt配置过程

    最近需要安装个mantisbt,由于不想再安装个apache服务器,因此直接使用iis作为php解析服务器.同时为了方便管理安装包,将php安装包和扩展包能够独立存放在D:\Program Files ...

  8. U3D 抛物线的方法

    本文转载:http://www.manew.com/thread-44642-1-1.html 无论是愤怒的小鸟,还是弓箭发射功能,亦或者模拟炮弹受重力影响等抛物线轨迹,都可以使用本文的方法,模拟绝对 ...

  9. Java 之文件IO编程 之写入

    package com.sun; /* * 操作对文件IO的写 * 2014-08-10 */ import java.io.*; public class File_Write { public s ...

  10. Update Statistics用法

    Update Statistics语句的作用将创建的数据库表的有关统计信息更新到系统 sysmater的相关表中,以便查询优化器选择最佳的执行路径,当sysmaster库中没有相应的统计信息,或者统计 ...