在项目中,时常会遇到存在上下级关系的数据。在呈现方面,按照传统方法,不得不组装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. 在网上浏览.NET的所有代码,并且让你的Visual Studio的go to definition(F12)指向在线代码

    博客搬到了fresky.github.io - Dawei XU,请各位看官挪步.最新的一篇是:在网上浏览.NET的所有代码,并且让你的Visual Studio的go to definition(F ...

  2. iOS使用技能 - 短信,语言验证码的获取与验证小结

    最近有学习一个小技能,这里小结一下,分享给大家,互相交流. 首先是大体步骤: 在mob官网注册,然后添加短信验证的应用 使用cocoapods导入框架 Podfile文件: platform :ios ...

  3. 课程助理For Windows(预览版,正方教务系统学生查分工具)

    其实盖子已经开发了一个功能更强大的版本,但是那个版本依然基于正方系统,也就是说只要正方系统跪了或者张院士在网站上做点手脚,这个小工具就会失效. 今天给大家的版本虽然功能及其简单.界面极端丑陋,但是通过 ...

  4. 在Excel里如何将多个工作簿合并到一个工作簿中

    在Excel里如何将多个工作簿合并到一个工作簿中 当你必须将多个工作簿合并到一个工作簿时,你遇到过麻烦吗?最让人心烦的就是需要合并的工作簿里有很多张工作表.有人能推荐方法解决这个问题吗? 利用VBA ...

  5. PL/SQL:使用pragma restrict_references限制包权限

    在看别人的代码的时候.发现了例如以下的编译指令. pragma restrict_references(get_attribute_name, wnds); get_attribute_name是一个 ...

  6. 经典SQL语句大全之基本函数

    SQL Server基本函数 1.字符串函数 长度与分析用 1,datalength(Char_expr) 返回字符串包含字符数,但不包含后面的空格2,substring(expression,sta ...

  7. 微信支付 V3版

    本人小菜鸟一仅仅.为了自我学习和交流PHP(jquery,linux,lamp,shell,javascript,server)等一系列的知识,小菜鸟创建了一个群.希望光临本博客的人能够进来交流. 寻 ...

  8. javascript、jsp

    1.javascript:简称js 在<body>与 </body>之间 加入<script> </script>即可 最好在<head>与 ...

  9. WPF加载Winform窗体时 报错:子控件不能为顶级窗体

    一.wpf项目中引用WindowsFormsIntegration和System.Windows.Forms 二.Form1.Designer.cs 的 partial class Form1 设置为 ...

  10. Oracle11g - dos 命令 sqlplus/nolog 提示 不是内部命令解决办法

    继安装Oracle 11g后,解锁SCOtt时发现 dos 命令 sqlplus/nolog 提示 不是内部命令解决办法   通过实际验证现整理有效方法步骤如下: 步骤一:开始>>找到Or ...