在项目中,时常会遇到存在上下级关系的数据。在呈现方面,按照传统方法,不得不组装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项目中,代码如下:
1 using Microsoft.Practices.Prism.ViewModel; 2 using System; 3 using System.Collections; 4 using System.Collections.Generic; 5 using System.Collections.ObjectModel; 6 using System.Linq; 7 using System.Runtime.Serialization; 8 using System.Text; 9 10 namespace SysManager.Utility 11 { 12 public class TreeNode: NotificationObject where T : BaseEntity 13 { 14 private T _parentNode; 15 private T _currentNode; 16 private bool _isChecked; 17 private bool _canChecked; 18 19 /// 20 /// 父节点 21 /// 22 public dynamic Key { get; set; } 23 24 ///25 /// 子节点 26 /// 27 public ObservableCollection> ChildrenNodes { get; set; } 28 29 /// 30 /// 是否允许被选中 31 /// 32 public bool CanChecked 33 { 34 get { return _canChecked; } 35 set 36 { 37 if (_canChecked == value) 38 return; 39 _canChecked = value; 40 RaisePropertyChanged("CanChecked"); 41 } 42 } 43 44 ///45 /// 是否处于被选中状态 46 /// 47 public bool IsChecked 48 { 49 get { return _isChecked; } 50 set 51 { 52 if (_isChecked == value) 53 return; 54 _isChecked = value; 55 RaisePropertyChanged("IsChecked"); 56 } 57 } 58 ///59 /// 当前选中节点 60 /// 61 public T CurrentNode 62 { 63 get { return _currentNode; } 64 set 65 { 66 if (_currentNode == value) 67 return; 68 _currentNode = value; 69 RaisePropertyChanged("CurrentNode"); 70 } 71 } 72 ///73 /// 当前节点的父级节点 74 /// 75 public T ParentNode 76 { 77 get { return _parentNode; } 78 set 79 { 80 if (_parentNode == value) 81 return; 82 _parentNode = value; 83 RaisePropertyChanged("ParentNode"); 84 } 85 } 86 87 public TreeNode() 88 { 89 this.CanChecked = true; 90 } 91 92 static TreeNodestaticNode; 93 94 /// 95 /// 将数据组织成一个拥有上下级管理的树形结构数据集合 96 /// 97 ///主键的数据类型 98 /// 执行过GroupBy语句的数据源 99 /// 结果数据100 /// 子节点标识字段名称101 /// 父节点标识字段名称102 /// 103 ///已生成的树形结构实体 104 public TreeNodeGenerateTreeNodes (IEnumerable > nodeSource, TreeNode resultTreeNode, string keyName, string parentKeyName)105 {106 var orderedSource = nodeSource.OrderBy(groupList => groupList.Key);107 foreach (IGrouping item in orderedSource)108 {109 var listChildrenNode = new ObservableCollection >();110 object propertyParentValue = null;111 112 foreach (var child in item)113 {114 //get children id 115 object propertyValue = GetCurrentItemPropertyValue(keyName, child);116 //get parent id 117 if (propertyParentValue == null)118 propertyParentValue = GetCurrentItemPropertyValue(parentKeyName, child);119 120 if (propertyValue != propertyParentValue)121 {122 T parentNodeInstance = null;123 if (propertyParentValue != null)124 {125 var nodeParent = nodeSource.Where(x => x.Key.ToString() == propertyParentValue.ToString()).FirstOrDefault();126 if (nodeParent != null)127 parentNodeInstance = nodeParent.FirstOrDefault();128 }129 var node = new TreeNode () { CurrentNode = child, Key = propertyValue, ChildrenNodes = new ObservableCollection >(), ParentNode = parentNodeInstance };130 listChildrenNode.Add(node);131 }132 133 }134 135 TreeNode parentNode = null;136 foreach (var root in listChildrenNode)137 {138 staticNode = null;139 parentNode = FindParentNode(resultTreeNode, item.Key);140 if (parentNode != null)141 break;142 }143 if (parentNode != null)144 {145 parentNode.ChildrenNodes = listChildrenNode;146 }147 else148 listChildrenNode.ToList().ForEach(childNode => resultTreeNode.ChildrenNodes.Add(childNode));149 150 }151 return resultTreeNode;152 }153 154 /// 155 /// 将一个拥有上下级关系的Tree转换为列表156 /// 157 public IEnumerable TreeNode2LinkedList { get; private set; }158 ///159 /// 将treenode转换为列表160 /// 161 ///162 /// 163 public void TreeNodeToLinkedList(TreeNode originalSource)164 {165 if (originalSource != null && originalSource.ChildrenNodes != null)166 {167 if (originalSource.CurrentNode != null)168 {169 if (TreeNode2LinkedList == null)170 TreeNode2LinkedList = new List ();171 (TreeNode2LinkedList as List ).Add(originalSource.CurrentNode);172 }173 foreach (var item in originalSource.ChildrenNodes)174 {175 TreeNodeToLinkedList(item);176 }177 }178 }179 180 private static object GetCurrentItemPropertyValue(string keyName, T child)181 {182 var property = child.GetType().GetProperties().Where(prop => prop.Name == keyName).FirstOrDefault();183 object propertyValue = null;184 if (property != null)185 propertyValue = property.GetValue(child, null);186 return propertyValue;187 }188 189 /// 190 /// 寻找当前节点的父级节点191 /// 192 /// 当前节点193 /// 节点的Key194 ///父级节点 195 private TreeNodeFindParentNode(TreeNode rootNode, dynamic key)196 {197 198 if (rootNode.ChildrenNodes == null)199 return rootNode;200 foreach (var children in rootNode.ChildrenNodes)201 {202 if (children.Key == key)203 {204 staticNode = children;205 break;206 }207 else208 if (staticNode == null)209 FindParentNode(children, key);210 }211 if (rootNode.Key != null && (int)rootNode.Key == key)212 return rootNode;213 214 return staticNode;215 216 }217 }218 }
//调用方法var treeNode = new TreeNode(); treeNode.GenerateTreeNodes (result.OfType ().GroupBy(proj => proj.ParentProjectId), treeNode, "ProjectId", "ParentProjectId");