ID OrderNum DeepNum Category
8 1 1 类一
9 2 2 类二
10 3 2 类三
11 4 3 类四
12 5 2 类五
13 6 1 类六
14 7 2 类七
15 8 3 类八……
我想按照DeepNum的顺序缩进绑定TreeView,类一到类八按照OrderNum的顺序排序。其中OrderNum和DeepNum的值可以无限扩展。显示的结果如下:+:类一 
|____:类二 
|____:类三 
|____|____:类四 
|____:类五 
+:类六 
|____:类七 
|____|____:类八 ……高难度问题,如果谁帮我解决了我单独奖励200分给他。UP有分。

解决方案 »

  1.   

    这个问题好解决,建议搜贴吧,treeview的帖子很多
      

  2.   

    http://www.cnblogs.com/chating/archive/2004/12/29/83669.html
      

  3.   

    树形结构在开发中的应用    lihonggen0(原作)  
      
    关键字     树、TreeView 
      
    树形结构在开发中的应用
    撰文: 李洪根本文首发于《CSDN开发高手》2003年第十二期 
     
    概述
    TreeView是一个重要的控件,无论是在VB.NET,C# 还是VB、Delphi等各种语言中,都充当了导航器的作用。在实际工作中,很多情况下需要将TreeView与数据库进行连接,以填充其节点。在Windows Form和Web Form中,我们可以用TreeView来显示树形结构,如显示目录树、显示地区、分类显示商品等。可以说,在大部分软件的开发中,TreeView都是一个不可缺少的展示控件。因此,树形结构的设计就成了软件开发人员一个永恒的话题。
    树形结构的展示方式
    树形结构的展示一般来讲有三种方式:
    1.         界面设计时在TreeView设计器或者代码中直接填充TreeView控件。
    2.         从XML文件中建立树形结构。
    3.         从数据库中得到数据,建立树形结构。
    第一种方式是最简单的,这种方式主要用于树形结构一般没有变化的应用程序,在设计时就固定一颗树。当然,在设计时固定了树的结构,以后要想修改、增加、删除树的节点,就必须修改源程序。所有不利于扩展。
    第二种方式从XML文件中提取,由于XML本身就是树形结构的,微软提供的文档对象模型DOM 可以方便的读取、操作和修改 XML 文档。在.NET中,应用System.Xml类可以方便地将XML文件加载到TreeView控件中,微软的MSDN也提供了实例,此处就不再多说。
    第三种方式,树形结构的数据,从数据库中获得。一般来讲,我们的应用程序多数是基于数据库的。采用这种方式,增加、修改、删除一颗树的节点很方便,只要操作数据库中的数据就可以了。而且,这种方式可以和数据库中的其它表做关联、查询和汇总,通过设计视图或存储过程,很容易查询出你想要的相关数据。下面,我们主要讨论这种方式的设计和实现。
    数据库设计
    首先,我们在SQL SERVER 2000里建立一个表tbTree,表的结构设计如下:
    列名 数据类型 描述 长度 主键 
    ID Int 节点编号 4 是 
    ConText Nvarchar 我们要显示的节点内容 50   
    ParentID Int 父节点编号 4   
    Depth Int 深度 4   关于Depth(深度)字段,主要是存放节点的层数,也就是说这个节点在树中的哪个层。有Depth(深度)字段,我们编程时会比较方便,在SQL查询时只有加一个where 条件就可以查询出当前深度的层的所有节点。如果我们不设计Depth(深度)字段,同样可以做类似的查询,这就需要在后台的SQL 查询中用循环处理。或者,你可以不在后台数据库服务器端处理,把这些处理放在前台。下面我们将介绍这几种处理方式:
     
    在SQL SERVER 2000中建表的脚本:
    CREATE TABLE [dbo].[tbTree] (       [ID] [int] IDENTITY (1, 1) NOT NULL ,       [Context] [nvarchar] (50) COLLATE Chinese_PRC_CI_AS NULL ,       [ParentID] [int] NULL ) ON [PRIMARY] 
    在表中添加如下记录:
     
     
    SET IDENTITY_INSERT tbtree ONinsert tbtree (ID,Context,ParentID)  values ( 1,'中国',0)insert tbtree (ID,Context,ParentID)  values ( 2,'北京',11)insert tbtree (ID,Context,ParentID)  values ( 3,'天津',1)insert tbtree (ID,Context,ParentID)  values ( 4,'河北省',1)insert tbtree (ID,Context,ParentID)  values ( 5,'广东省',1)insert tbtree (ID,Context,ParentID)  values ( 6,'广州',5)insert tbtree (ID,Context,ParentID)  values ( 7,'四川省',1)insert tbtree (ID,Context,ParentID)  values ( 8,'成都',7)insert tbtree (ID,Context,ParentID)  values ( 9,'深圳',5)insert tbtree (ID,Context,ParentID)  values ( 10,'石家庄',4)insert tbtree (ID,Context,ParentID)  values ( 11,'辽宁省',1)insert tbtree (ID,Context,ParentID)  values ( 12,'大连',11)insert tbtree (ID,Context,ParentID)  values ( 13,'上海',1)insert tbtree (ID,Context,ParentID)  values ( 14,'天河软件园',6)insert tbtree (ID,Context,ParentID)  values ( 15,'汕头',5)SET IDENTITY_INSERT tbtree off有Depth(深度)字段时在VB6 中的实现 :
      我们看一下,用ADD方法添加一个新节点到TreeView的节点集合,语法如下: 
      Nodes.Add(relative,[relationship][,key][,text][,image][,selectedimage]) 
    从上面的语法,可以看出添加一个节点,只需要知道父节点编号的key,就可以通过这个key添加子节点。
        如果数据库中查询出来的结果集中是按Depth (深度)列排序的话,就可以先加第一层的节点、再加第二层的节点….一直到第N层。所以,下文我写了一个AddTree函数,参数是层数(深度),RS是打开小于等于此层数的所有记录,并按层数排序。所以一层一层地添加,通过循环记录集,就可以完成一颗树。够简单吧!
     
     
    Dim CN As ADODB.Connection                '定义数据库的连接Dim Rs As ADODB.Recordset '工程--->引用--->Microsoft ActiveX Data Object 2.x(版本号)Private Sub Form_Load()    Set CN = New ADODB.Connection       ‘连接数据库    CN.ConnectionString = "Provider=sqloledb;Data Source=pmserver;Initial Catalog=Bench;User Id=sa;Password=sa;"    CN.OpenCall AddTree(3)End Sub Private Sub AddTree(ByVal intDepth As Integer)       ‘打开记录集,得到深度小于些深度的所有节点,并按深度排序    Set Rs = New ADODB.Recordset    Rs.Open "select * from tbTree where depth<='" & intDepth & "' order by depth", CN, adOpenDynamic, adLockReadOnly    Dim Xnod As Node    Do While Not Rs.EOF        If Rs.Fields("depth") = 0 Then                     ‘加入根结点            Set Xnod = TreeView1.Nodes.Add(, , "key" & Rs.Fields("id"), Rs.Fields("context"))        Else                     ‘加入子节点            Set Xnod = TreeView1.Nodes.Add("key" & Rs.Fields("parentid"), tvwChild, "key" & Rs.Fields("id"), Rs.Fields("context"))        End If        Xnod.EnsureVisible        Rs.MoveNext    Loop    Rs.CloseEnd Sub 
    程序运行结果如下图所示:
     
      

  4.   

    没有Depth(深度)时的实现
    上面的程序完全是依靠Depth这一列,如果没有深度这一列来排序,可以看出,上面的代码就会出错!
    从tbTree表的设计可以看出,如果没有Depth这一列,只要有ID字段和ParentID字段就可以查询到一个节点下的所有节点,答案是肯定的!看我们下面这个存储过程,其作用就是你只要传一个ID号,就可以找出下面的所有节点!而且这些节点是按层次排序的!
     
    建立存储过程:
    CREATE PROCEDURE  spGetTree (       @ID int)asset nocount ondeclare @tmp table (Id int,ConText varchar(50),ParentID int,depth int)insert @tmp select * from tbtree where ID=@IDwhile exists(select 1 from tbtree a,@tmp b where a.ParentID=b.ID and a.ID not in (select ID from @tmp))  insert @tmp select a.* from  tbtree a,@tmp b where a.ParentID=b.ID and a.ID not in (select ID from @tmp)select * from @tmpset nocount offGO 剖析:上面的存储过程,While语句就是一层一层地将地将树的节点插入到目的表@tmp中。有兴趣的读者可以自行跟踪一下。 
    我们利用上面这个存储过程,可以很容易地用VB6写出添加树状结构的代码,因为这个存储过程得到的数据是已经按层次排好序的,我们只要循环记录集,顺序添加节点就可以。
     
    Private Sub AddTreeEx(ByVal intID As Integer)    Set Rs = New ADODB.Recordset    Rs.Open "spGettree " & intID, CN, adOpenDynamic, adLockReadOnly    Dim Xnod As Node    Do While Not Rs.EOF        If Rs.Fields("parentID") = 0 Then            Set Xnod = TreeView1.Nodes.Add(, , "key" & Rs.Fields("id"), Rs.Fields("context"))        Else            Set Xnod = TreeView1.Nodes.Add("key" & Rs.Fields("parentid"), tvwChild, "key" & Rs.Fields("id"), Rs.Fields("context"))        End If        Xnod.EnsureVisible        Rs.MoveNext    Loop    Rs.CloseEnd Sub 在VB.NET中实现
        在.NET中,由于TreeView控件的用法和VB6中的用法是不一样的!以前的VB6程序员会因为节点没有Key属性而烦恼!在.NET中,TreeView树的节点是一个集合,每个 TreeNode 都可以包含其他 TreeNode 对象的集合。要确定您在树结构中的位置,得使用 FullPath 属性。
        我们知道,添加节点只能是在找到节点之后再此节点下添加。现在VB.NET少了Key属性,对操作是一个很大的不便。微软MSDN有一篇文章用继承和重载的方法,扩展了TreeView控件,给节点加了一个key属性。有兴趣的读者可以看一下HOW TO:Create a Key Property for a TreeView Node in Visual Basic .NET这篇文章。但是美中不足的是:这篇文章只是为TreeNode加了一个NodeKey属性,但是没有提供好的Key值检索功能。尽管这一切我们都可以用代码来扩展,但是代码冗长。
        所以,添加许多层节点的树形结构,只能是递归调用。而且,我们下面的代码很精炼,只需要传给递归过程一个ParentID,就会将这个编号下的所有节点加载到树形结构中!充分体现了:简单就是好的思想。
        设计思想:从数据库中查询到所有节点的记录,添加到DataView中,利用DataView的.RowFilter属性得到某个父节点编号ParentID下的所有记录,依次递归循环。
     
    在VB.net中实现:
        Private ds As New DataSet ()' AddTree递归函数每次都要用到数据集中的一个表,所以定义成private    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load        ' '定义数据库连接        Dim CN As New SqlConnection()        Try          '初始化连接字符串            CN.ConnectionString = "data source=pmserver;initial catalog=Bench;persist security info=False;user id=sa;Password=sa;"            CN.Open()                '添加命令,从数据库中得到数据            Dim sqlCmd As New SqlCommand()            sqlCmd.Connection = CN            sqlCmd.CommandText = "select * from tbtree"            sqlCmd.CommandType = CommandType.Text            Dim adp As SqlDataAdapter = New SqlDataAdapter(sqlCmd)            adp.Fill(ds)        Catch ex As Exception            MsgBox(ex.Message)        Finally          '关闭连接            CN.Close()        End Try        '调用递归函数,完成树形结构的生成        AddTree(0, Nothing)    End Sub     '&#768;递归添加树的节点    Private Sub AddTree(ByVal ParentID As Integer, ByVal pNode As TreeNode)        Dim Node As TreeNode        Dim dvTree As New DataView()        dvTree = New DataView(ds.Tables(0))        '过滤ParentID,得到当前的所有子节点        dvTree.RowFilter = "PARENTID = " + ParentID.ToString         Dim Row As DataRowView        For Each Row In dvTree            If pNode Is Nothing Then  '判断是否根节点                '&#768;添加根节点                Node = TreeView1.Nodes.Add(Row("context").ToString())                            '&#768;再次递归                AddTree(Int32.Parse(Row("ID").ToString()), Node)            Else                ‘添加当前节点的子节点                Node = pNode.Nodes.Add(Row("context").ToString())                            '&#768;再次递归                AddTree(Int32.Parse(Row("ID").ToString()), Node)            End If            Node.EnsureVisible()        Next    End Sub程序运行结果如下图所示:
     
    在C# 中实现:
           有了在VB.NET中实现的代码,我们只要改成C#的语法就可以了:
                   DataSet ds=new DataSet();
                  private void Form1_Load(object sender, System.EventArgs e)
                  {
                         // 定义数据库连接
                         SqlConnection CN = new SqlConnection();
                         try 
                         {
                                //初始化连接字符串
                                CN.ConnectionString= "data source=pmserver;initial catalog=Bench;persist security info=False;user id=sa;Password=sa;";
                                CN.Open();
                                //添加命令,从数据库中得到数据
                                SqlCommand sqlCmd= new SqlCommand();
                                sqlCmd.Connection = CN;
                                sqlCmd.CommandText = "select * from tbTree";
                                sqlCmd.CommandType = CommandType.Text ;
                                SqlDataAdapter adp = new SqlDataAdapter(sqlCmd);
                                adp.Fill(ds);
                         }
                         catch (Exception ex)
                         {
                                throw (ex);   
                         }
                         finally 
                         {
                                CN.Close();
                         }
                         //调用递归函数,完成树形结构的生成
                         AddTree(0, (TreeNode)null);
                  }
     
                  // 递归添加树的节点
                  public void AddTree(int ParentID,TreeNode pNode) 
                  {
                         DataView dvTree = new DataView(ds.Tables[0]);
                         //过滤ParentID,得到当前的所有子节点
                         dvTree.RowFilter =  "[PARENTID] = " + ParentID;
                         foreach(DataRowView Row in dvTree) 
                         {
                                if(pNode == null) 
                                {    //'&#768;添加根节点
                                       TreeNode Node = treeView1.Nodes.Add(Row["ConText"].ToString());
                                       AddTree(Int32.Parse(Row["ID"].ToString()),Node);    //再次递归
                                } 
                                else 
                                {   //添加当前节点的子节点
                                       TreeNode Node =  pNode.Nodes.Add(Row["ConText"].ToString());
                                       AddTree(Int32.Parse(Row["ID"].ToString()),Node);     //再次递归
                                }
                         }                   
                  }            
     
    后记:请读者自行修改程序中的连接字符串设置。
    附:相关微软MSDN文档,包括在VB6和.NET中从XML建立树形结构 
    http://support.microsoft.com/default.aspx?kbid=311318http://support.microsoft.com/default.aspx?kbid=308063http://support.microsoft.com/default.aspx?kbid=317597http://support.microsoft.com/default.aspx?kbid=244954 
      

  5.   

    表结构不对
    ID OrderNum DeepNum Category
    8 1 1 类一
    9 2 2 类二
    10 3 2 类三
    11 4 3 类四
    12 5 2 类五
    13 6 1 类六
    14 7 2 类七
    15 8 3//如果把这里改为10怎么办: 类八
    表改为这样要好一些
    ID OrderNum 父类的id Category
    8 1 0 类一
    9 2 8 类二
    10 3 8 类三
    11 4 11 类四
    12 5 8 类五
    13 6 0 类六
    14 7 13 类七
    15 8 14 类八
      

  6.   

    没有Depth(深度)时的实现
    上面的程序完全是依靠Depth这一列,如果没有深度这一列来排序,可以看出,上面的代码就会出错!
    从tbTree表的设计可以看出,如果没有Depth这一列,只要有ID字段和ParentID字段就可以查询到一个节点下的所有节点,答案是肯定的!看我们下面这个存储过程,其作用就是你只要传一个ID号,就可以找出下面的所有节点!而且这些节点是按层次排序的!
     
    建立存储过程:
    CREATE PROCEDURE  spGetTree (       @ID int)asset nocount ondeclare @tmp table (Id int,ConText varchar(50),ParentID int,depth int)insert @tmp select * from tbtree where ID=@IDwhile exists(select 1 from tbtree a,@tmp b where a.ParentID=b.ID and a.ID not in (select ID from @tmp))  insert @tmp select a.* from  tbtree a,@tmp b where a.ParentID=b.ID and a.ID not in (select ID from @tmp)select * from @tmpset nocount offGO 剖析:上面的存储过程,While语句就是一层一层地将地将树的节点插入到目的表@tmp中。有兴趣的读者可以自行跟踪一下。 
    我们利用上面这个存储过程,可以很容易地用VB6写出添加树状结构的代码,因为这个存储过程得到的数据是已经按层次排好序的,我们只要循环记录集,顺序添加节点就可以。
     
    Private Sub AddTreeEx(ByVal intID As Integer)    Set Rs = New ADODB.Recordset    Rs.Open "spGettree " & intID, CN, adOpenDynamic, adLockReadOnly    Dim Xnod As Node    Do While Not Rs.EOF        If Rs.Fields("parentID") = 0 Then            Set Xnod = TreeView1.Nodes.Add(, , "key" & Rs.Fields("id"), Rs.Fields("context"))        Else            Set Xnod = TreeView1.Nodes.Add("key" & Rs.Fields("parentid"), tvwChild, "key" & Rs.Fields("id"), Rs.Fields("context"))        End If        Xnod.EnsureVisible        Rs.MoveNext    Loop    Rs.CloseEnd Sub 在VB.NET中实现
        在.NET中,由于TreeView控件的用法和VB6中的用法是不一样的!以前的VB6程序员会因为节点没有Key属性而烦恼!在.NET中,TreeView树的节点是一个集合,每个 TreeNode 都可以包含其他 TreeNode 对象的集合。要确定您在树结构中的位置,得使用 FullPath 属性。
        我们知道,添加节点只能是在找到节点之后再此节点下添加。现在VB.NET少了Key属性,对操作是一个很大的不便。微软MSDN有一篇文章用继承和重载的方法,扩展了TreeView控件,给节点加了一个key属性。有兴趣的读者可以看一下HOW TO:Create a Key Property for a TreeView Node in Visual Basic .NET这篇文章。但是美中不足的是:这篇文章只是为TreeNode加了一个NodeKey属性,但是没有提供好的Key值检索功能。尽管这一切我们都可以用代码来扩展,但是代码冗长。
        所以,添加许多层节点的树形结构,只能是递归调用。而且,我们下面的代码很精炼,只需要传给递归过程一个ParentID,就会将这个编号下的所有节点加载到树形结构中!充分体现了:简单就是好的思想。
        设计思想:从数据库中查询到所有节点的记录,添加到DataView中,利用DataView的.RowFilter属性得到某个父节点编号ParentID下的所有记录,依次递归循环。
     
    在VB.net中实现:
        Private ds As New DataSet ()' AddTree递归函数每次都要用到数据集中的一个表,所以定义成private    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load        ' '定义数据库连接        Dim CN As New SqlConnection()        Try          '初始化连接字符串            CN.ConnectionString = "data source=pmserver;initial catalog=Bench;persist security info=False;user id=sa;Password=sa;"            CN.Open()                '添加命令,从数据库中得到数据            Dim sqlCmd As New SqlCommand()            sqlCmd.Connection = CN            sqlCmd.CommandText = "select * from tbtree"            sqlCmd.CommandType = CommandType.Text            Dim adp As SqlDataAdapter = New SqlDataAdapter(sqlCmd)            adp.Fill(ds)        Catch ex As Exception            MsgBox(ex.Message)        Finally          '关闭连接            CN.Close()        End Try        '调用递归函数,完成树形结构的生成        AddTree(0, Nothing)    End Sub     '&#768;递归添加树的节点    Private Sub AddTree(ByVal ParentID As Integer, ByVal pNode As TreeNode)        Dim Node As TreeNode        Dim dvTree As New DataView()        dvTree = New DataView(ds.Tables(0))        '过滤ParentID,得到当前的所有子节点        dvTree.RowFilter = "PARENTID = " + ParentID.ToString         Dim Row As DataRowView        For Each Row In dvTree            If pNode Is Nothing Then  '判断是否根节点                '&#768;添加根节点                Node = TreeView1.Nodes.Add(Row("context").ToString())                            '&#768;再次递归                AddTree(Int32.Parse(Row("ID").ToString()), Node)            Else                ‘添加当前节点的子节点                Node = pNode.Nodes.Add(Row("context").ToString())                            '&#768;再次递归                AddTree(Int32.Parse(Row("ID").ToString()), Node)            End If            Node.EnsureVisible()        Next    End Sub程序运行结果如下图所示:
     
    在C# 中实现:
           有了在VB.NET中实现的代码,我们只要改成C#的语法就可以了:
                   DataSet ds=new DataSet();
                  private void Form1_Load(object sender, System.EventArgs e)
                  {
                         // 定义数据库连接
                         SqlConnection CN = new SqlConnection();
                         try 
                         {
                                //初始化连接字符串
                                CN.ConnectionString= "data source=pmserver;initial catalog=Bench;persist security info=False;user id=sa;Password=sa;";
                                CN.Open();
                                //添加命令,从数据库中得到数据
                                SqlCommand sqlCmd= new SqlCommand();
                                sqlCmd.Connection = CN;
                                sqlCmd.CommandText = "select * from tbTree";
                                sqlCmd.CommandType = CommandType.Text ;
                                SqlDataAdapter adp = new SqlDataAdapter(sqlCmd);
                                adp.Fill(ds);
                         }
                         catch (Exception ex)
                         {
                                throw (ex);   
                         }
                         finally 
                         {
                                CN.Close();
                         }
                         //调用递归函数,完成树形结构的生成
                         AddTree(0, (TreeNode)null);
                  }
     
                  // 递归添加树的节点
                  public void AddTree(int ParentID,TreeNode pNode) 
                  {
                         DataView dvTree = new DataView(ds.Tables[0]);
                         //过滤ParentID,得到当前的所有子节点
                         dvTree.RowFilter =  "[PARENTID] = " + ParentID;
                         foreach(DataRowView Row in dvTree) 
                         {
                                if(pNode == null) 
                                {    //'&#768;添加根节点
                                       TreeNode Node = treeView1.Nodes.Add(Row["ConText"].ToString());
                                       AddTree(Int32.Parse(Row["ID"].ToString()),Node);    //再次递归
                                } 
                                else 
                                {   //添加当前节点的子节点
                                       TreeNode Node =  pNode.Nodes.Add(Row["ConText"].ToString());
                                       AddTree(Int32.Parse(Row["ID"].ToString()),Node);     //再次递归
                                }
                         }                   
                  }            
     
    后记:请读者自行修改程序中的连接字符串设置。
    附:相关微软MSDN文档,包括在VB6和.NET中从XML建立树形结构 
    http://support.microsoft.com/default.aspx?kbid=311318http://support.microsoft.com/default.aspx?kbid=308063http://support.microsoft.com/default.aspx?kbid=317597http://support.microsoft.com/default.aspx?kbid=244954
      

  7.   

    没有Depth(深度)时的实现
    上面的程序完全是依靠Depth这一列,如果没有深度这一列来排序,可以看出,上面的代码就会出错!
    从tbTree表的设计可以看出,如果没有Depth这一列,只要有ID字段和ParentID字段就可以查询到一个节点下的所有节点,答案是肯定的!看我们下面这个存储过程,其作用就是你只要传一个ID号,就可以找出下面的所有节点!而且这些节点是按层次排序的!
     
    建立存储过程:
    CREATE PROCEDURE  spGetTree (       @ID int)asset nocount ondeclare @tmp table (Id int,ConText varchar(50),ParentID int,depth int)insert @tmp select * from tbtree where ID=@IDwhile exists(select 1 from tbtree a,@tmp b where a.ParentID=b.ID and a.ID not in (select ID from @tmp))  insert @tmp select a.* from  tbtree a,@tmp b where a.ParentID=b.ID and a.ID not in (select ID from @tmp)select * from @tmpset nocount offGO 剖析:上面的存储过程,While语句就是一层一层地将地将树的节点插入到目的表@tmp中。有兴趣的读者可以自行跟踪一下。 
    我们利用上面这个存储过程,可以很容易地用VB6写出添加树状结构的代码,因为这个存储过程得到的数据是已经按层次排好序的,我们只要循环记录集,顺序添加节点就可以。
     
    Private Sub AddTreeEx(ByVal intID As Integer)    Set Rs = New ADODB.Recordset    Rs.Open "spGettree " & intID, CN, adOpenDynamic, adLockReadOnly    Dim Xnod As Node    Do While Not Rs.EOF        If Rs.Fields("parentID") = 0 Then            Set Xnod = TreeView1.Nodes.Add(, , "key" & Rs.Fields("id"), Rs.Fields("context"))        Else            Set Xnod = TreeView1.Nodes.Add("key" & Rs.Fields("parentid"), tvwChild, "key" & Rs.Fields("id"), Rs.Fields("context"))        End If        Xnod.EnsureVisible        Rs.MoveNext    Loop    Rs.CloseEnd Sub 在VB.NET中实现
        在.NET中,由于TreeView控件的用法和VB6中的用法是不一样的!以前的VB6程序员会因为节点没有Key属性而烦恼!在.NET中,TreeView树的节点是一个集合,每个 TreeNode 都可以包含其他 TreeNode 对象的集合。要确定您在树结构中的位置,得使用 FullPath 属性。
        我们知道,添加节点只能是在找到节点之后再此节点下添加。现在VB.NET少了Key属性,对操作是一个很大的不便。微软MSDN有一篇文章用继承和重载的方法,扩展了TreeView控件,给节点加了一个key属性。有兴趣的读者可以看一下HOW TO:Create a Key Property for a TreeView Node in Visual Basic .NET这篇文章。但是美中不足的是:这篇文章只是为TreeNode加了一个NodeKey属性,但是没有提供好的Key值检索功能。尽管这一切我们都可以用代码来扩展,但是代码冗长。
        所以,添加许多层节点的树形结构,只能是递归调用。而且,我们下面的代码很精炼,只需要传给递归过程一个ParentID,就会将这个编号下的所有节点加载到树形结构中!充分体现了:简单就是好的思想。
        设计思想:从数据库中查询到所有节点的记录,添加到DataView中,利用DataView的.RowFilter属性得到某个父节点编号ParentID下的所有记录,依次递归循环。
     
    在VB.net中实现:
        Private ds As New DataSet ()' AddTree递归函数每次都要用到数据集中的一个表,所以定义成private    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load        ' '定义数据库连接        Dim CN As New SqlConnection()        Try          '初始化连接字符串            CN.ConnectionString = "data source=pmserver;initial catalog=Bench;persist security info=False;user id=sa;Password=sa;"            CN.Open()                '添加命令,从数据库中得到数据            Dim sqlCmd As New SqlCommand()            sqlCmd.Connection = CN            sqlCmd.CommandText = "select * from tbtree"            sqlCmd.CommandType = CommandType.Text            Dim adp As SqlDataAdapter = New SqlDataAdapter(sqlCmd)            adp.Fill(ds)        Catch ex As Exception            MsgBox(ex.Message)        Finally          '关闭连接            CN.Close()        End Try        '调用递归函数,完成树形结构的生成        AddTree(0, Nothing)    End Sub     '&#768;递归添加树的节点    Private Sub AddTree(ByVal ParentID As Integer, ByVal pNode As TreeNode)        Dim Node As TreeNode        Dim dvTree As New DataView()        dvTree = New DataView(ds.Tables(0))        '过滤ParentID,得到当前的所有子节点        dvTree.RowFilter = "PARENTID = " + ParentID.ToString         Dim Row As DataRowView        For Each Row In dvTree            If pNode Is Nothing Then  '判断是否根节点                '&#768;添加根节点                Node = TreeView1.Nodes.Add(Row("context").ToString())                            '&#768;再次递归                AddTree(Int32.Parse(Row("ID").ToString()), Node)            Else                ‘添加当前节点的子节点                Node = pNode.Nodes.Add(Row("context").ToString())                            '&#768;再次递归                AddTree(Int32.Parse(Row("ID").ToString()), Node)            End If            Node.EnsureVisible()        Next    End Sub程序运行结果如下图所示:
     
    在C# 中实现:
           有了在VB.NET中实现的代码,我们只要改成C#的语法就可以了:
                   DataSet ds=new DataSet();
                  private void Form1_Load(object sender, System.EventArgs e)
                  {
                         // 定义数据库连接
                         SqlConnection CN = new SqlConnection();
                         try 
                         {
                                //初始化连接字符串
                                CN.ConnectionString= "data source=pmserver;initial catalog=Bench;persist security info=False;user id=sa;Password=sa;";
                                CN.Open();
                                //添加命令,从数据库中得到数据
                                SqlCommand sqlCmd= new SqlCommand();
                                sqlCmd.Connection = CN;
                                sqlCmd.CommandText = "select * from tbTree";
                                sqlCmd.CommandType = CommandType.Text ;
                                SqlDataAdapter adp = new SqlDataAdapter(sqlCmd);
                                adp.Fill(ds);
                         }
                         catch (Exception ex)
                         {
                                throw (ex);   
                         }
                         finally 
                         {
                                CN.Close();
                         }
                         //调用递归函数,完成树形结构的生成
                         AddTree(0, (TreeNode)null);
                  }
     
                  // 递归添加树的节点
                  public void AddTree(int ParentID,TreeNode pNode) 
                  {
                         DataView dvTree = new DataView(ds.Tables[0]);
                         //过滤ParentID,得到当前的所有子节点
                         dvTree.RowFilter =  "[PARENTID] = " + ParentID;
                         foreach(DataRowView Row in dvTree) 
                         {
                                if(pNode == null) 
                                {    //'&#768;添加根节点
                                       TreeNode Node = treeView1.Nodes.Add(Row["ConText"].ToString());
                                       AddTree(Int32.Parse(Row["ID"].ToString()),Node);    //再次递归
                                } 
                                else 
                                {   //添加当前节点的子节点
                                       TreeNode Node =  pNode.Nodes.Add(Row["ConText"].ToString());
                                       AddTree(Int32.Parse(Row["ID"].ToString()),Node);     //再次递归
                                }
                         }                   
                  }            
     
    后记:请读者自行修改程序中的连接字符串设置。
    附:相关微软MSDN文档,包括在VB6和.NET中从XML建立树形结构 
    http://support.microsoft.com/default.aspx?kbid=311318http://support.microsoft.com/default.aspx?kbid=308063http://support.microsoft.com/default.aspx?kbid=317597http://support.microsoft.com/default.aspx?kbid=244954
      

  8.   

    private void InitTree(TreeNodeCollection Nds,string parentId)
    {
    DataView dv=new DataView();
    TreeNode tmpNd;
    string intId;
    dv.Table=dset.Tables["tree"];
    dv.RowFilter="ParentId='" + parentId + "'" ;
    foreach(DataRowView drv in dv)
        {   
    if (objnode=="1")
    {
    this.groupid.Text=drv["NodeId"].ToString();
    objnode="2";
    }
    tmpNd=new TreeNode();
    tmpNd.ID=drv["NodeId"].ToString();
    tmpNd.Text=drv["NodeName"].ToString();
    tmpNd.ImageUrl="img/"+drv["Icon"].ToString();
    tmpNd.Expanded=true;
    Nds.Add(tmpNd);
    intId=drv["ParentId"].ToString();
    InitTree(tmpNd.Nodes,tmpNd.ID);
    }
    }
      

  9.   

    根据楼主的需求写的,如果没有非法数据的话(像hdt(接分接出个星星)说的那样),应该是可以的
    ==============================================================
    Imports System.Collections.Specialized
    Imports Microsoft.Web.UI.WebControls
    Public Class TestTreeView
        Inherits System.Web.UI.Page#Region " Web 窗体设计器生成的代码 "
    '''该处代码省略
    #End Region    Dim arr As ArrayList
        Dim Pnd As TreeNodeCollection
        Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            arr = New ArrayList        arr.Add(New Item(1, " 类一"))
            arr.Add(New Item(2, "类二"))        arr.Add(New Item(2, "类三"))
            arr.Add(New Item(3, "类四"))
            arr.Add(New Item(2, "类五"))
            arr.Add(New Item(1, "类六"))
            arr.Add(New Item(2, "类七"))
            arr.Add(New Item(3, "类八"))
            Dim i As Integer
            Pnd = TreeView1.Nodes
            For i = 0 To arr.Count - 1
                AddNode(i, arr(i))
            Next    End Sub
        Private Sub AddNode(ByVal index As Integer, ByVal Itm As Item)
            ''todo 如果插入节点深度>现有深度+1,那么直接退出
            Dim nd As New TreeNode
            nd.ID = index
            nd.NodeData = Itm._level
            nd.Text = Itm._text
            If Itm._level = 1 Then ''如果是顶层节点
                TreeView1.Nodes.Add(nd)
                Pnd = nd.Nodes
                Exit Sub
            End If
            If Itm._level <= CType(Pnd.Parent, TreeNode).NodeData Then
                Dim i As Integer
                For i = 0 To CType(Pnd.Parent, TreeNode).NodeData - Itm._level
                    Pnd = CType(CType(Pnd.Parent, TreeNode).Parent, TreeNode).Nodes
                Next
            End If
            Pnd.Add(nd)
            Pnd = nd.Nodes
        End Sub
    End Class'''用于记录节点的深度和文本Public Class Item
        Public _level As Integer
        Public _text As String    Public Sub New(ByVal ID As Integer, ByVal Text As String)
            _level = ID
            _text = Text
        End SubEnd Class
      

  10.   

    上面的arraylist用于模拟楼主的数据源
      

  11.   

    因为这个问题价值千金,要是解决了我就能开发出一个排序法无限分类组件,到时候能卖个好价钱。
    该组件界面超简单,http://www.flash8.net/bbs/UploadFile/2005-3/200539215613418.jpg
    所有对类的操作都浓缩在这张图里,但要实现起来却是困难重重。
      

  12.   

    这个简单。
    加一个ParentID。递归就可以了。
      

  13.   

    我写了个绑定,但好象有点错,高手帮忙看看错在哪里。 private void tvCategoryBind()
    {
    Db.Category myCategory = new Category();
    SqlDataReader dr1 = myCategory.drMaxOrderNum();
    if(dr1.Read())
    {
    maxOrderNum = dr1.GetInt32(0);//取得最大OrderNum
    }
    else
    {
    maxOrderNum = 0;
    } //Response.Write(maxOrderNum);

    SqlDataReader dr2 = myCategory.drMaxDeepNum();
    if(dr2.Read())
    {
    maxDeepNum = dr2.GetInt32(0);//取得最小DeepNum
    }
    else
    {
    maxDeepNum = 0;
    } //Response.Write(maxDeepNum); DataSet ds = myCategory.dsSelectOrderBy(); int i;
    int r; for(r=0;r<maxOrderNum;r++) 

    for(i=0;i<maxDeepNum;i++) 
    {       
    if(i<maxDeepNum) 

    ds.Tables[0].Rows[i][2] = "0" + ds.Tables[0].Rows[i][2];

    else 

    ds.Tables[0].Rows[i][2] = ds.Tables[0].Rows[i][2];

    TreeNode myNode = new TreeNode();
    myNode.Text = ds.Tables[0].Rows[i][3].ToString();
    myNode.Expanded = true;
    tvCategory.Nodes.Add(myNode);
    }
    }
    }
      

  14.   

    艾,VB语法我写的比较顺手么,呵呵。你要早说要C#代码我就不用VB.Net了
      

  15.   

    靠,研究了一个下午终于搞定了无限分类的树状显示。 DataSet ds = myCategory.dsSelectOrderBy();
    for(int i=0;i<ds.Tables[0].Rows.Count;i++)
    {
    if(int.Parse(ds.Tables[0].Rows[i][2].ToString())==1)
    {
    ds.Tables[0].Rows[i][3] = ds.Tables[0].Rows[i][3].ToString();
    }
    else
    {
    for(int j=1;j<int.Parse(ds.Tables[0].Rows[i][2].ToString());j++)
    {
    ds.Tables[0].Rows[i][3] = "|-" + ds.Tables[0].Rows[i][3].ToString();
    }
    }
    }
    ddlCategory.DataSource = ds.Tables[0].DefaultView;
    ddlCategory.DataTextField = ds.Tables[0].Columns[3].ToString();
    ddlCategory.DataValueField = ds.Tables[0].Columns[3].ToString();
    ddlCategory.DataBind();
      

  16.   

    只要拿个堆栈来记录 DeepNum和对应的纪录key, 然后依次处理记录
        While(栈顶DeepNum>=当前DeepNum)出栈;
        记录加到栈顶记录下
        当前DeepNum/Key进栈
    直到所有记录完成这样就可以了,并不是很复杂啊
      

  17.   

    只需定义一个 层次节点数组,lastnode[1..最大可能的深度]
    用来保存某个深度的最后一个节点
    对于下一个节点,总是其深度值-1的对应lastnode的子节点
      

  18.   

    这有什么难的,递归一下就可以了!但如果你直接使用从DB中取可能会产生POOL不够用的情况,
    建议你从DB将所有数据搜索出来后,再在数据集里面处理递归
      

  19.   

    if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[Board]') and OBJECTPROPERTY(id, N'IsUserTable') = 1) 
    drop table [dbo].[Board] 
    GO 
     
    CREATE TABLE [dbo].[Board] ( 
     [BoardId] [int] IDENTITY (1, 1) NOT NULL , 
     [PareId] [int] NOT NULL , 
     [BoardName] [varchar] (50) COLLATE Chinese_PRC_CI_AS NULL , 
     [BoardMark] [varchar] (255) COLLATE Chinese_PRC_CI_AS NULL  
    ) ON [PRIMARY] 
    GO 
    得到树的深度存储过程:
    CREATE PROCEDURE dbo.SpBoardTreeDepth 
    AS 
       declare @level int 
       declare @t table(boardid int,pareid int,boardname varchar(50),level int) 
       set @level = 1 
       insert into @t select boardid,pareid,boardname,@level from board where pareid = 0 
       while(@@rowcount>0) 
          begin 
            set @level=@level+1 
            insert into @t 
              select a.boardid,a.pareid,a.boardname,@level from board a 
              join @t b on a.pareid = b.boardid where b.level=@level-1 
          end 
          select boardid,pareid,boardname,level from @t 
          RETURN 
    GO 绑定到TreeView控件:
    private System.Windows.Forms.TreeView treeView1; 
     
    public Form1() 

     // 
     // Windows 窗体设计器支持所必需的 
     // 
     InitializeComponent(); 
     
     // 
     // TODO: 在 InitializeComponent 调用后添加任何构造函数代码 
     // 
     
     DataTable dt = Popo.Dal.SqlHelp.LoadData("SpBoardTreeDepth",null).Tables[0]; 
     string rootId = "0"; 
     CreateChild(treeView1.Nodes,rootId,dt); 

     
    void CreateChild(TreeNodeCollection nodeCollection,string id ,DataTable dt){ 
     if(dt.Rows.Count == 0) 
      return; 
     for(int i=0;i<dt.Rows.Count;i++){ 
      DataRow dr = dt.Rows[i]; 
      if(dr["pareid"].ToString() == id){ 
       string deep = "" ; 
       for(int j=0;j<System.Convert.ToInt32(dr["level"].ToString())-1;j++){ 
        deep +="&nbsp;&nbsp;"; 
       } 
       deep += "┣ "; 
       TreeNode node = new TreeNode(dr["boardname"].ToString()); 
       node.Tag = dr["boardid"].ToString(); 
       nodeCollection.Add(node); 
       string bId = dr["boardid"].ToString(); 
       dt.Rows.Remove(dt.Rows[i]); 
       CreateChild(node.Nodes,bId,dt); 
       CreateChild(nodeCollection,id,dt); 
      } 
     } 

      

  20.   

    DEEPNUM应该设计成PARENTID这样比较好做