原来我的数据库中的结构是这样的:
class表:C_id     ParentsId     C_class   
1        0             软件工程
2        0             网络编程
3        0             C#程序设计
4        1             第一章
5        1             第二章
6        2             第一章
7        2             第二章
8        2             第三章
9        3             第一章
10       3             第二章用TreeView控件绑定 想使之效果为:第一级节点显示课程的名称 然后他们下面可以展开他们的章节,比如软件工程有 第一章 第二章 ;网络编程有 第一章 第二章 第三章 。上面这样的数据库结构配合下面的程序,可以实现这个效果。
private void Page_Load(object sender, System.EventArgs e)
{
if(!Page.IsPostBack)
{
string SqlConn=System.Configuration.ConfigurationSettings.AppSettings["ConnString"];
Conn=new SqlConnection(SqlConn);
CreateDataSet();
InitTree(this.TreeView1.Nodes,"0");
}
private DataSet CreateDataSet()
{
SqlStr="select * from class";
da=new SqlDataAdapter(SqlStr,Conn);
data=new DataSet();
da.Fill(data,"tree");
return data;
}
private void InitTree(TreeNodeCollection Nds,string parentId)
{
TreeNode tmpNd;
DataRow[] rows=data.Tables[0].Select("ParentId='"+parentId+"'");
foreach(DataRow row in rows)
{
tmpNd=new TreeNode();
tmpNd.ID=row["C_id"].ToString();
tmpNd.Text=row["C_class"].ToString();
tmpNd.NavigateUrl="index.aspx?class="+row["parentId"].ToString()+"&C_id="+row["C_id"].ToString();
Nds.Add(tmpNd);
InitTree(tmpNd.Nodes,tmpNd.ID);
}
}
这样做主要思想是,先从表里找出根节点的数据,然后生成TreeNode节点插入到TreeView中,然后用第归寻找当前节点的子节点,生成TreeNode并插入到TreeView中。这样做是可以的。
但我想从新设计一下数据库,让它更容易理解些。我想做成这样:
C_id     NodeId     C_class   
1        第一章     软件工程
2        第二章     软件工程
3        第三章     软件工程  
4        第一章     C#程序设计
5        第二章     C#程序设计
6        第三章     C#程序设计
7        第一章     网络编程
8        第二章     网络编程现在想这样做数据库或者需要再加一些节点(比如ParentId),来达到同样的效果,也就是第一级级节点显示课程名称 然后他们有多少章节 就可以展开看到。
基本就是这样,我想了一天,高手们,帮我指点一下。我现在主要困惑的问题是,怎么样插入课程的章节到它所在的课程名称节点下!

解决方案 »

  1.   

    顶一下,顺便修正一下,数据库表中的ParentsId ==>ParentId
      

  2.   

    推荐一篇相关的文章-ASP.NET2.0 中实现 Treeview 与数据库绑定(含代码):
    http://www.why100000.com/_articles/show_a_article.asp?autoid=36&tab=tabAspNet
      

  3.   

    我对treeview用的比较熟悉,请参观一下效果:
    http://www.addtoo.net/Visitor/View.aspx
    数据库树形结构我参考的是这篇文章:
    http://www.sitepoint.com/article/hierarchical-data-database/2
      

  4.   

    给你一个例子        /// <summary>
            /// 生成树
            /// </summary>
            /// <param name="iUserID">用户ID</param>
            /// <param name="trvMenu">菜单Tree</param>
            /// <param name="iMenuID">菜单ID</param>
            /// <param name="iMenuRightCount">有权限的数目</param>
            public void GenerateTree(int iUserID, TreeView trvMenu, int iMenuID, out int iMenuRightCount)
            {
                iMenuRightCount = 0;
                DataGroup dgAllMenus = this.GetUserMenus(iUserID);            if ( dgAllMenus == null )   //如果查询时出现错误, 只添加退出菜单            {
                    TreeNode rootNode = new TreeNode();
                    rootNode.Text       = "退出";
                    rootNode.NodeData   = "";
                    rootNode.Expanded   = true; 
                    trvMenu.Nodes.Add(rootNode);                TreeNode nodLoginAgain = new TreeNode();
                    nodLoginAgain.Text        = "重新登录";
                    nodLoginAgain.NodeData    = "";
                    nodLoginAgain.NavigateUrl = "Login.aspx?Type=LoginAgain";
                    rootNode.Nodes.Add(nodLoginAgain);                TreeNode nodQuit = new TreeNode();
                    nodQuit.Text     = "<div onclick='window.close();'>退出系统</div>";
                    nodQuit.NodeData = "";
                    rootNode.Nodes.Add(nodQuit);                return;
                }            //获取一级菜单            
                DataView  dvRootMenu = new DataView(dgAllMenus.Table, "MenuLevel = 1", "DisplayNo", DataViewRowState.CurrentRows);
              
                if (dvRootMenu.Count == 0)  //没有权限,只显示退出
                {
                    iMenuRightCount = 0;
                    
                    TreeNode rootNode = new TreeNode();
                    rootNode.Text       = "退出";
                    rootNode.NodeData   = "";
                    rootNode.Expanded   = true; 
                    trvMenu.Nodes.Add(rootNode);                TreeNode nodLoginAgain = new TreeNode();
                    nodLoginAgain.Text        = "重新登录";
                    nodLoginAgain.NodeData    = "";
                    nodLoginAgain.NavigateUrl = "Login.aspx?Type=LoginAgain";
                    rootNode.Nodes.Add(nodLoginAgain);                TreeNode nodQuit = new TreeNode();
                    nodQuit.Text     = "<div onclick='window.close();'>退出系统</div>";
                    nodQuit.NodeData = "";
                    rootNode.Nodes.Add(nodQuit);
                }
                else  //有权限
                {
                    iMenuRightCount = 1;                string[] strMenuIDPath = this.GetMenuIDPath(iMenuID); //Get Menu ID Path
                    string strNodeIndex = "";                for (int i=0; i<dvRootMenu.Count; i++)
                    {
                        //添加一级菜单
                        TreeNode firstNode = new TreeNode();
                        firstNode.Text      = dvRootMenu[i]["MenuName"].ToString();
                        firstNode.NodeData  = dvRootMenu[i]["MenuID"].ToString();
                        firstNode.Expanded  = true;
                        trvMenu.Nodes.Add(firstNode);                    if (strMenuIDPath[0] != "-1")
                        {
                            for (int j=0; j<strMenuIDPath.Length; j++)
                            {
                                if (strMenuIDPath[j] == firstNode.NodeData)
                                {
                                    strNodeIndex = i.ToString();
                                    break;
                                }
                            }
                        }
                        
                        this.CreateNode(Int32.Parse(dvRootMenu[i]["MenuID"].ToString()), 2, firstNode, dgAllMenus.Table, strMenuIDPath, ref strNodeIndex);
                    }                TreeNode rootNode = new TreeNode();
                    rootNode.Text       = "退出";
                    rootNode.NodeData   = "";
                    rootNode.Expanded   = true; 
                    trvMenu.Nodes.Add(rootNode);                TreeNode nodLoginAgain = new TreeNode();
                    nodLoginAgain.Text        = "重新登录";
                    nodLoginAgain.NodeData    = "";
                    nodLoginAgain.NavigateUrl = "Login.aspx?Type=LoginAgain";
                    rootNode.Nodes.Add(nodLoginAgain);                TreeNode nodQuit = new TreeNode();
                    nodQuit.Text     = "<div onclick='window.close();'>退出系统</div>";
                    nodQuit.NodeData = "";
                    rootNode.Nodes.Add(nodQuit);                if (strMenuIDPath[0] != "-1")
                    {
                        try
                        {
                            trvMenu.SelectedNodeIndex = strNodeIndex;
                        }
                        catch
                        {
                        }
                    }
                }
            }        /// <summary>
            /// 循环生成树的结构
            /// </summary>
            /// <param name="fatherID">上一级菜单ID</param>
            /// <param name="menuLevel">菜单级数</param>
            /// <param name="parentNode">上一级的Node</param>
            /// <param name="dtMenu">DataTable</param>
            /// <param name="strMenuIDPath">Menu ID Path</param>
            /// <param name="strNodeIndex">Node Index</param>
            private void CreateNode(int fatherID, int menuLevel, TreeNode parentNode, DataTable dtMenu, string[] strMenuIDPath, ref string strNodeIndex)
            {
                DataRow[] drMenu = dtMenu.Select("FatherID = " + fatherID + " AND MenuLevel = " + menuLevel, "DisplayNo");
                
                int intIndex = 0;
                foreach (DataRow dr in drMenu)
                {
                    TreeNode curNode = new TreeNode();
                    curNode.Text     = dr["MenuName"].ToString();
                    curNode.NodeData = dr["MenuID"].ToString();                if (dr["MenuPath"].ToString() != "")
                    {
                        curNode.NavigateUrl = dr["MenuPath"].ToString();
                        curNode.Target      = "MainFrame";
                    }                if (strMenuIDPath[0] != "-1")
                    {
                        for (int i=0; i<strMenuIDPath.Length; i++)
                        {
                            if (strMenuIDPath[i] == curNode.NodeData)
                            {
                                strNodeIndex += "." + intIndex.ToString();
                                curNode.Expanded = true;
                                break;
                            }
                        }
                    }                parentNode.Nodes.Add(curNode);                  //添加下一级的菜单
                    CreateNode(Int32.Parse(dr["MenuID"].ToString()), menuLevel+1, curNode, dtMenu, strMenuIDPath, ref strNodeIndex);                intIndex++;
                }
            }
      

  5.   

    表还是用你第一个表,基本思路——循环生成父节点,递归生成子节点    
         /// <summary>
        /// 绑定父节点
        /// </summary>
        private void Bindclass()
        {
            class[] _m = Getclass();//实体类class。(属性说明自动提取数据库字段的描述信息)具体写法后面有
            foreach (class _l in _m)
            {
                // 循环生成根节点
                TreeNode n = new TreeNode(_l.mod_name);
                n.ToolTip = _l.mod_name;
                n.Value = _l.mod_id.ToString();
                n.SelectAction = TreeNodeSelectAction.None;
                tmpNd.Nodes.Add(n);
                CreateNode(n, _l);
            }
        }    /// <summary>
        /// 递归生成所有子节点
        /// </summary>
        /// <param name="p_Node">节点</param>
        /// <param name="p_class">模块</param>
        private void CreateNode(TreeNode p_Node, class p_class)
        {
            class[] _m = GetChildclass(p_class);
            foreach (class _l in _m)
            {
                TreeNode n = new TreeNode(_l.mod_name);
                n.ToolTip = _l.mod_name;
                n.Value = _l.mod_id.ToString();
                n.SelectAction = TreeNodeSelectAction.None;
                p_Node.ChildNodes.Add(n);
                CreateNode(n, _l);
            }
        }         /// <summary>
            /// 获取所有父模块
            /// </summary>
            /// <returns></returns>
            public class[] Getclass()
            {
                string SQL = "select C_id from class where (ParentsId = '0') ";
                return GetclassBySQL(SQL);
            }        /// <summary>
            /// 获取父模块下的子模块
            /// </summary>
            /// <param name="p_class">父模块</param>
            /// <returns></returns>
            public class[] GetChildclass(class p_class)
            {
                if (p_class != null && p_class.C_id.ToString() != string.Empty)
                {
                    string SQL = "select C_id from class where ParentsId = '" + p_class.C_id + "' ";
                    return GetclassBySQL(SQL);
                }
                return new class[0];
            }         /// <summary>
            /// 获取模块数组
            /// </summary>
            /// <param name="p_SQL">SQL 语句</param>
            /// <returns></returns>
            private class [] GetclassBySQL(string p_SQL)
            {
                ArrayList _a = new ArrayList();
                DataTable objData = ado.GetDataTable(p_SQL);//此处就是获取一个datatable ,ado是我自己的数据库链接的类库
                for (int i = 0; i < objData.Rows.Count; i++)
                {
                    _a.Add(GetclassByID(objData.Rows[i]["C_id"].ToString()));
                }
                objData.Dispose();
                objData = null;
                return (class[])_a.ToArray(typeof(class));
            }         /// <summary>
            /// 获取一个class对象
            /// </summary>
            /// <param name="p_classID">classID</param>
            /// <returns></returns>
            public class GetclassByID(string p_classID)
            {
                if (p_classID != string.Empty)
                {
                    class m = new class();
                    string sql = "select * from class where (C_id = '"+p_classID+"') ";
                    DataTable objData = ado.GetDataTable(sql);//此处同样也是获取一个datatable
                    if (objData.Rows.Count > 0)
                    {
                        m.C_id= int.Parse(objData.Rows[0]["C_id"].ToString());
                        m.ParentsId= int.Parse(objData.Rows[0]["ParentsId"].ToString());
                        m.C_class  = objData.Rows[0]["C_class"].ToString();
                    }
                    objData.Dispose();
                    objData = null;
                    return m;
                }
                else
                    return (new class());
            }下面是实体类class的写法
        /// <summary>
        /// 实体类class。(属性说明自动提取数据库字段的描述信息)
        /// </summary>
        public class class
        {
            public class()
            { }
            private int _C_id;
            private int _ParentsId;
            private string _C_class;        /// <summary>
            /// 
            /// </summary>
            public int C_id
            {
                set { _C_id= value; }
                get { return _C_id; }
            }
            /// <summary>
            /// 
            /// </summary>
            public int ParentsId
            {
                set { _ParentsId = value; }
                get { return _ParentsId; }
            }
            /// <summary>
            /// 
            /// </summary>
            public string C_class
            {
                set { _C_class = value; }
                get { return _C_class; }
            }
    }
      

  6.   


    看看这个http://www.51aspx.com/CV/AjaxNodeTree/
      

  7.   

    有实例源码.邮箱[email protected]
      

  8.   

    http://www.why100000.com/_articles/show_a_article.asp?autoid=36&tab=tabAspNet