AutoCAD.NET 技术交流-吴锋


专注AutoCAD.net,GIS
posts - 113, comments - 500, trackbacks - 15, articles - 4
  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理

TreeView 树结构的断层处理

Posted on 2007-11-19 14:43 无锋不起浪 阅读(1884) 评论(6)  编辑 收藏 所属分类: Asp.net
    TreeView 生成最常见的一种编程实现方式就是通过“父子关系递归”生成树,一般是自顶向下递归生成。这种方法的缺陷:“由父节点及子节点”的遍历顺序意味着每个子节点的父节点必须存在,否则将搜索不到,即出现“断层现象”。
本文在递归原理的基础上,通过调节父节点的层次,解决树结构的断层问题。
   

一、递归生成树的算法:
#region 加载部门树*****************************************************
DataSet Dept_ds;
/// <summary>
/// 加载部门树
/// </summary>
public void DeptTree(TreeView tvMenu)
{
    Dept_ds 
= myData.GetDept();//执行 "select * from Sys_Department"
    DeptTree(tvMenu, 0, (TreeNode)null);
}

/// <summary>
/// 加载部门树
/// </summary>
private void DeptTree(TreeView tvMenu, int ParentID, TreeNode pNode)
{
    
string nodeId = "DeptID";
    
string nodeName = "DeptName";
    
string nodeParent = "DeptParent";

    DataView dvTree 
= new DataView(Dept_ds.Tables[0]);
    
//过滤nodeParent,得到当前的所有子节点
    dvTree.RowFilter = nodeParent + " = " + ParentID;
    
foreach (DataRowView drv in dvTree)
    {
        TreeNode newNode 
= new TreeNode();
        newNode.Text 
= drv[nodeName].ToString().Trim();
        newNode.ToolTip 
= drv[nodeName].ToString().Trim() + "[ID=" + drv[nodeId].ToString().Trim() + "]";
        newNode.Value 
= drv[nodeId].ToString().Trim();
        newNode.Target 
= "user";

        newNode.ImageUrl 
= ImagePath + "menu/dept.gif";
        newNode.NavigateUrl 
= "UserChoose_User.aspx?DeptID=" + drv[nodeId].ToString().Trim();

        
if (pNode == null)
        {   
//添加根节点
            newNode.SelectAction = TreeNodeSelectAction.SelectExpand;
            newNode.Expanded 
= false;
            newNode.PopulateOnDemand 
= false;

            tvMenu.Nodes.Add(newNode);
//***注意区别:根节点
            DeptTree(null, Int32.Parse(drv[nodeId].ToString().Trim()), newNode);//递归
        }
        
else
        {   
//?添加子节点
            newNode.SelectAction = TreeNodeSelectAction.SelectExpand;
            newNode.Expanded 
= false;
            newNode.PopulateOnDemand 
= false;

            pNode.ChildNodes.Add(newNode);
//***注意区别:子节点
            DeptTree(null, Int32.Parse(drv[nodeId].ToString().Trim()), newNode);//递归
        }
    }
}
#endregion

二、断层处理原理:
    遍历筛选后的数据表newTable,获取每个节点的所有父节点列表(从未经筛选的数据表oldTable中获取),判断父节点是否完整存在于newTable中。通过依次调整父节点的层次,保证每个节点的最上级父节点最终为根结点。
    递归算法性能上是有点影响,对较少的数据处理还是可以的。下面给出具体实现类:
namespace Framework.Helper
{
    
/// <summary>
    
/// 树形结构操作帮助类
    
/// </summary>
    public static class TreeHelper
    {
        
#region 重置数据表的父节点, 解决断层问题
        
/// <summary>
        
/// 重置数据表的父节点, 解决树形结构的断层问题
        
/// </summary>
        
/// <param name="newTable">筛选后的数据表</param>
        
/// <param name="oldTable">未经筛选的数据表</param>
        
/// <param name="IDField">节点ID字段</param>
        
/// <param name="ParentField">父节点ID字段</param>
        public static DataTable ResetParent(DataTable newTable, DataTable oldTable, string IDField, string ParentField)
        {
            
//行循环筛newTable
            for (int i = 0; i < newTable.Rows.Count; i++)
            {
                
int id = Convert.ToInt32(newTable.Rows[i][IDField]);
                
int parentID = Convert.ToInt32(newTable.Rows[i][ParentField]);
                
//获取指定节点在oldTable的所有父节点
                string[] arrParent = GetAllParent(id, oldTable, IDField, ParentField).Split(',');

                
//遍历oldTable中的所有父节点
                for (int j = 0; j < arrParent.Length - 1; j++)
                {
                    
//判断父节点是否在newTable中
                    if (HasNode(newTable, IDField, Convert.ToInt32(arrParent[j])))
                    {
                        
//若在,设置为父节点
                        newTable.Rows[i][ParentField] = Convert.ToInt32(arrParent[j]);
                        
break;
                    }
                    
else
                    {
                        
//不在,设置父节点为0
                        newTable.Rows[i][ParentField] = 0;
                        
continue;
                    }
                }
                
///通过这样的调整,若节点node的父节点不再newTable中,就设置node.Parent = node.Parent.Parent,依次类推。
            }

            
return newTable;
        }
        
/// <summary>
        
/// 判断指定ID的节点是否存在与指定数据表
        
/// </summary>
        public static bool HasNode(DataTable dt, string IDField, int id)
        {
            DataView dv 
= new DataView(dt);
            dv.RowFilter 
= IDField + "=" + id;
            
return (dv.Count > 0? true : false;
        }
        
#endregion

        
#region 获取指定节点的所有父节点
        
/// <summary>
        
/// 获取指定节点的所有父节点ID
        
/// </summary>
        
/// <param name="ID">指定节点ID</param>
        
/// <param name="dataTable">数据表</param>
        
/// <param name="IDField">节点ID</param>
        
/// <param name="ParentField">父节点ID</param>
        
/// <returns>字符串,并以逗号隔开</returns>
        public static string GetAllParent(int ID, DataTable dataTable, string IDField, string ParentField)
        {
            
string resultParent = "";
            GetAllParent(ID, dataTable, IDField, ParentField, 
ref resultParent);
            
return resultParent;
        }
        
private static void GetAllParent(int ID, DataTable dataTable, string IDField, string ParentField, ref string resultParent)
        {
            DataView dv 
= new DataView(dataTable);
            dv.RowFilter 
= IDField + "=" + ID;
            
int parentID = 0;
            
if (dv.ToTable().Rows.Count > 0)//***
                parentID = Convert.ToInt32(dv.ToTable().Rows[0][ParentField]);

            resultParent 
+= parentID + ",";
            
if (parentID > 0)
            {
                GetAllParent(parentID, dataTable, IDField, ParentField, 
ref resultParent);
            }
        }
        
#endregion
    }
}

三、如果sql语句有条件限制的话,即执行 "select * from Sys_Department where ...",则(一)中函数应改为:
public void DeptTree(TreeView tvMenu)
{
    Dept_ds1 
= myData.GetDept();//执行 "select * from Sys_Department"
    Dept_ds2 = myData.GetDept(strWhere);//执行 "select * from Sys_Department where "
    Dept_ds = Framework.Helper.TreeHelper.ResetParent(Dept_ds1, Dept_ds2, "DeptID""DeptParent");//调整父节点
    DeptTree(tvMenu, 0, (TreeNode)null);
}

Feedback

#1楼    回复  引用    

2007-11-19 15:23 by laji [未注册用户]
!
!!
!!!!
!!!!!!
!!!!!!!!
!!!!!!!!!!!
!!!!!!!!!!!!!
!!!!!!顶!!!!!!!

#2楼    回复  引用  查看    

2007-11-19 16:24 by Enzo      
顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶?????????顶顶
顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶???????????????顶顶
顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶??????????????????顶顶
顶顶顶顶顶顶顶顶顶顶顶????????????????顶顶顶顶顶顶顶顶
顶顶顶顶顶顶顶顶???????顶???顶顶?????顶顶顶顶顶顶顶顶顶
顶顶顶????????????顶顶顶顶顶顶????顶顶顶顶顶顶顶顶顶顶
顶??????????????顶顶顶顶顶顶????顶顶顶顶顶顶顶顶顶顶
顶????????????顶顶顶顶顶顶顶???????????顶顶顶顶
顶????????????顶顶顶顶顶顶??????????????顶顶
顶顶??????????顶顶顶顶顶??????顶顶顶???????顶顶
顶顶顶顶顶顶顶顶????顶顶顶顶????顶顶顶顶顶顶 ?????顶顶顶
顶顶顶顶顶顶顶顶????顶顶顶顶????顶顶??顶顶顶?????顶顶顶
顶顶顶顶顶顶顶顶????顶顶顶顶????顶顶????顶?????顶顶顶
顶顶顶顶顶顶顶顶????顶顶顶顶????顶顶????顶?????顶顶顶
顶顶顶顶顶顶顶顶????顶顶顶顶????顶顶???顶顶?????顶顶顶
顶顶顶顶顶顶顶顶????顶顶顶顶????顶顶???顶顶?????顶顶顶
顶顶顶顶顶顶顶顶????顶顶顶顶????顶????顶顶?????顶顶顶
顶顶顶顶顶顶顶顶????顶顶顶顶????顶????顶顶?????顶顶顶
顶顶顶顶顶顶顶顶????顶顶顶顶????顶????顶顶?????顶顶顶
顶顶顶顶顶顶顶顶????顶顶顶顶????顶????顶顶?????顶顶顶
顶顶顶顶顶顶顶顶????顶顶顶顶???顶顶????顶顶?????顶顶顶
顶顶??顶顶顶?????顶顶顶顶???顶顶???顶顶顶?????顶顶顶
顶顶??????????顶顶顶顶顶??顶顶??顶顶顶顶?????顶顶顶
顶顶顶?????????顶顶顶顶顶顶顶顶???顶顶顶顶顶????顶顶顶
顶顶顶顶顶???????顶顶顶顶顶顶顶顶???顶????顶顶顶顶顶顶顶
顶顶顶顶顶顶??????顶顶顶顶顶顶顶????顶顶?????顶顶顶顶顶
顶顶顶顶顶顶顶顶顶???顶顶顶顶顶顶?????顶顶顶???????顶顶
顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶??????顶顶顶顶顶??????顶顶
顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶??????顶顶顶顶顶顶???????顶
顶顶顶顶顶顶顶顶顶顶顶顶顶顶?????顶顶顶顶顶顶顶顶顶??????顶
顶顶顶顶顶顶顶顶顶顶顶顶顶?????顶顶顶顶顶顶顶顶顶顶顶????顶顶

just for fun

#3楼    回复  引用  查看    

2007-11-19 16:25 by Clark Zheng      
看看我这种树型算法怎么样? *_^
http://www.cnblogs.com/reonlyrun/archive/2006/12/30/641052.html

#4楼    回复  引用    

2007-11-19 22:12 by 洁斌 [未注册用户]
这样很麻烦~直接在控件继承类中建立绑定数据就好了
更简单方便

#5楼 [楼主]   回复  引用  查看    

2007-11-20 08:14 by 无锋不起浪      
那你提供绑定的数据是怎样来的?

#6楼    回复  引用  查看    

2007-11-21 11:32 by Bao      
断了层那还是树么。。。。森林了吧。。。

标题  
姓名  
主页
Email (博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2007-12-18 11:49 编辑过
Google站内搜索


相关链接: