using System; using System.Collections.Generic; using System.Text; using System.Web; using Zhaizj.Framework.Web; namespace Zhaizj.Framework { /// /// 树状节点接口 /// public interface INode { /// /// 节点的 Id /// int Id { get; set; } /// /// 节点的名称 /// String Name { get; set; } /// /// 上级节点的 Id /// int ParentId { get; set; } } /// /// 节点绑定器 /// public interface INodeBinder { String Bind( INode node ); } /// /// 树状节点(将 T 做了封装,便于操作) /// /// 节点必须实现了 INode 接口 public class Node where T : INode { public Node() { } public Node( T node ) { _rawNode = node; } private T _rawNode; /// /// 获取原始节点数据 /// /// public T getNode() { return _rawNode; } //----------------------------------------------------- private Tree _tree; public void setTree( Tree tree ) { _tree = tree; } private Node _parent; /// /// 获取上级节点 /// /// public Node getParent() { if (this.getNode().ParentId == 0) return null; if (_parent == null) { _parent = _tree.FindById( this.getNode().ParentId ); } return _parent; } private int _depth = -1; /// /// 获取节点的深度 /// /// public int getDepth() { if (_depth < 0) { if (this.getNode().ParentId == 0) { _depth = 0; } else { if (this.getParent() == null) { _depth = 0; } else { _depth = this.getParent().getDepth() + 1; } } } return _depth; } private List> _children = new List>(); /// /// 获取所有子节点 /// /// public List> getChildren() { return _children; } internal void addChildren( Node node ) { _children.Add( node ); } //------------------------------------------------------------- private Node _prevNode; private Node _nextNode; /// /// 获取前一个节点 /// /// public Node getPrev() { return _prevNode; } /// /// 获取后一个节点 /// /// public Node getNext() { return _nextNode; } internal void setPrev( Node node ) { _prevNode = node; } internal void setNext( Node node ) { _nextNode = node; } internal Boolean indent() { if (getPrev() == null) return true; return getDepth() > getPrev().getDepth(); } internal Boolean outdent() { if (getPrev() == null) return false; return getDepth() < getPrev().getDepth(); } internal int getOutdentCount() { return getPrev().getDepth() - getDepth(); } } /// /// 树状结构 /// /// 节点必须实现了 INode 接口 public class Tree where T : INode { private static readonly ILog logger = LogManager.GetLogger( "Zhaizj.Framework.Tree" ); private List _rawList; public Tree( List nodeList ) { _rawList = nodeList; initProxyList(); } //------------------------------------------------------------ /// /// 根据 Id 检索节点 /// /// /// public Node FindById( int id ) { return getById( id ); } /// /// 根据 Id 获取它的上级节点 /// /// /// public Node FindParent( int id ) { Node proxy = getById( id ); if (proxy == null) return default( Node ); return proxy.getParent(); } /// /// 根据 Id,获取它的节点路径(从根级开始到当前节点) /// /// /// public List> FindPath( int id ) { List> nodePath = new List>(); Node proxy = getById( id ); if (proxy == null) return nodePath; nodePath.Add( proxy ); Node currentNode = proxy; while (true) { Node parent = currentNode.getParent(); if (parent == null) break; nodePath.Add( parent ); currentNode = parent; } nodePath.Reverse(); return nodePath; } /// /// 获取所有根节点 /// /// public List> FindRoots() { return getRoots(); } /// /// 根据 Id,获取所有子节点 /// /// /// public List> FindChildren( int id ) { Node proxy = getById( id ); if (proxy == null) return new List>(); return proxy.getChildren(); } private List> _allOrdered; /// /// 获取所有节点(经过排序) /// /// public List> FindAllOrdered() { if (_allOrdered == null) { List> results = new List>(); List> roots = this.FindRoots(); foreach (Node node in roots) { addSubProxyNodes( results, node ); } _allOrdered = results; } return _allOrdered; } private void addSubProxyNodes( List> results, Node parentnode ) { results.Add( parentnode ); List> subnodes = parentnode.getChildren(); foreach (Node node in subnodes) { addSubProxyNodes( results, node ); } } //------------------------------------------------------------ /// /// 根据 Id 获取节点 /// /// /// public T GetById( int id ) { Node proxy = getById( id ); if (proxy != null) return proxy.getNode(); return default( T ); } /// /// 根据 Id 获取节点的深度 /// /// /// public int GetDepth( int id ) { Node proxy = getById( id ); if (proxy != null) return proxy.getDepth(); return 0; } /// /// 根据 Id 获取上级节点 /// /// /// public T GetParent( int id ) { Node proxy = getById( id ); if (proxy == null) return default( T ); Node parentProxy = proxy.getParent(); if (parentProxy != null) return parentProxy.getNode(); return default( T ); } /// /// 根据 Id,获取节点的路径(从根级开始到当前节点) /// /// /// public List GetPath( int id ) { List nodePath = new List(); Node proxy = getById( id ); if (proxy == null) return nodePath; nodePath.Add( proxy.getNode() ); Node tempNode = proxy; while (true) { Node parent = tempNode.getParent(); if (parent == null) break; nodePath.Add( parent.getNode() ); tempNode = parent; } nodePath.Reverse(); return nodePath; } /// /// 根据 Id,获取所有下级节点 /// /// /// public List GetChildren( int id ) { Node proxy = getById( id ); if (proxy == null) return new List(); List> children = proxy.getChildren(); List results = new List(); foreach (Node px in children) results.Add( px.getNode() ); return results; } /// /// 获取所有根节点 /// /// public List GetRoots() { List> nodes = this.FindRoots(); List results = new List(); foreach (Node px in nodes) { results.Add( px.getNode() ); } return results; } private List _allOrderedNode; /// /// 获取所有排序过的节点 /// /// public List GetAllOrdered() { if (_allOrderedNode == null) { List> nodes = this.FindAllOrdered(); List results = new List(); foreach (Node px in nodes) { results.Add( px.getNode() ); } _allOrderedNode = results; } return _allOrderedNode; } //---------------------------------------------------------------- /// /// 树状下拉列表控件 /// /// 下拉列表name /// 当前选定的值 /// public String DropList( String dropName, int selectValue ) { return DropList( dropName, selectValue, 0, null ); } /// /// 获取下拉列表select /// /// 下拉列表的name和id /// 当前选中项的值 /// 当select用于设置父节点之时,此参数表示将节点自己排除在下拉列表之外,防止将自己作为自己的父节点 /// 根节点(并不存在,但你可以给它取个名称) /// public String DropList( String dropName, int selectValue, int nodeId, String rootSelectName ) { List> list = this.FindAllOrdered(); StringBuilder builder = new StringBuilder(); builder.AppendFormat( "" ); return builder.ToString(); } private static String getBlank( int depth ) { StringBuilder builder = new StringBuilder(); int length = depth * 4; for (int i = 0; i <= length; i++) { builder.Append( " " ); } return builder.ToString(); } private static int getSelectedValue( String dropName, int val ) { if (CurrentRequest.getHttpMethod().Equals( "POST" )) { return cvt.ToInt( CurrentRequest.getForm( dropName ) ); } return val; } /// /// 获取树状结构的 html /// /// /// public String RenderList( String treeId ) { return RenderList( treeId, true, null, 0 ); } /// /// 获取树状结构的 html /// /// /// /// /// /// public String RenderList( String treeId, Boolean showChildren, INodeBinder binder, int currentNodeId ) { List> list = this.FindAllOrdered(); StringBuilder builder = new StringBuilder(); int indent = 0; for (int i = 0; i < list.Count; i++) { Node node = list[i]; // 是否添加 ul 以及是否隐藏 if (i == 0) { builder.Append( "
    " ); indent++; } else if (node.indent()) { String displayCls = getDisplayCls( showChildren, currentNodeId, node.getNode().Id ); builder.Append( "" ); indent++; } else if (node.outdent()) { int outdentCount = node.getOutdentCount(); for (int x = 0; x < outdentCount; x++) { builder.Append( "
" ); indent--; } } // li 的 class builder.Append( "" ); String item = (binder == null ? node.getNode().Name : binder.Bind( node.getNode() )); builder.Append( item ); builder.Append( "" ); } for (int y = 0; y < indent; y++) { builder.Append( "" ); } return builder.ToString(); } private String getListClass( Boolean showChildren, int currentNodeId, Node node ) { String cls = ""; if (node.getChildren().Count > 0) { cls += "parentNode"; if (isOpenedNode( currentNodeId, node.getNode().Id, showChildren )) cls += " collapseNode"; else cls += " expandNode"; } if (node.getNode().Id == currentNodeId) cls += " currentNode"; return cls.Trim(); } private String getDisplayCls( Boolean showChildren, int currentNodeId, int nodeId ) { if (showChildren) return ""; List> path = FindPath( currentNodeId ); foreach (Node parent in path) { if (parent.getNext() == null) continue; if (nodeId == parent.getNext().getNode().Id) return ""; } return " class=\"hide\""; } private Boolean isOpenedNode( int currentNodeId, int nodeId, Boolean showChildren ) { if (showChildren) return true; List> path = FindPath( currentNodeId ); foreach (Node parent in path) { if (nodeId == parent.getNode().Id) return true; } return false; } //---------------------------------------------------------------- private Node getById( int id ) { if (getIdCache().ContainsKey( id ) == false) return default( Node ); return getIdCache()[id]; } //---------------------------------------------------------------- private List> _proxyList; private Dictionary> _idcache; private List> _roots; private List> getNodeList() { return _proxyList; } private Dictionary> getIdCache() { return _idcache; } private List> getRoots() { return _roots; } private void initProxyList() { _proxyList = new List>(); _idcache = new Dictionary>(); _roots = new List>(); // 缓存id foreach (T node in _rawList) { Node proxy = new Node( node ); proxy.setTree( this ); _proxyList.Add( proxy ); _idcache.Add( node.Id, proxy ); } // 缓存children foreach (Node node in _proxyList) { if (node.getNode().ParentId == 0) { _roots.Add( node ); } else { Node p = node.getParent(); if (p == null) { logger.Error( string.Format( "parent does not exist: id={0}, name={1}, parentId={2}", node.getNode().Id, node.getNode().Name, node.getNode().ParentId ) ); } else { p.addChildren( node ); } } } // 排序并缓存pre和next List> orderedList = FindAllOrdered(); for (int i = 0; i < orderedList.Count; i++) { if (i == 0) continue; Node node = orderedList[i]; Node pre = orderedList[i - 1]; node.setPrev( pre ); pre.setNext( node ); } } } }