菜鸟请教C# 如何动态追加到treeview的对应子节点上

各位大大们好,我是才学一个月的新手,这个问题研究一天了,搞不定,查了好多资料也没搞定. 

数据库是sql server2008版本的, 语言是C#

数据库结构就像图上这样,每个类别最大有四级分支,需要动态的加载到winform上.第一级很好加上去,可是第二级起我不知道如果让0101饮料类找到他的父节点01上,关键是想实现如下这张图的效果,

 

肯请指点下,只要教我会做到二级就可以了.三四级应该是重复的,菜鸟谢谢各位大神了

 

首先,你的表里数据的数据需要建立起连接,你的表缺少一个父节点字段,

id no name version pid

pid就是父节点,根节点是0 ,叶节点的父节点是它上级节点的id

程序里你取出表中数据,然后如下

try
            {
                // 加根节点
                TreeNode Node = new TreeNode()
                {
                    Tag = -1,
                    ImageIndex = 0,
                    Text = "食品"
                };
                foreach (string name in 取数据的方法)
                {
                    TreeNode CNode = new TreeNode()
                    {
                        ImageIndex = 2,
                        SelectedImageIndex = 3,
                        Tag = no,
                        Text = name
                    };
                    Node.Nodes.Add(CNode);
                }
                TreeView.Nodes.Add(Node);
            }
            catch (Exception ex)
            {
                LogHelper.WriteLog(GlobleHelper.ErrorLog, "处理treeview出错:" + ex, GlobleHelper.WriteLog);
            }

即是学习,给几个建议吧

1、树型结构在数据库里必然要存储节点的父节点编号,而不应该是通过计算才能得到,这会大降低代码效率,也会增加编码难度

2、树型处理不可避免的要用到递归方法

 

谢谢大家,我的问题已解决,这里分享下学习所得,也方便后面的菜鸟.

在@Water Lee和@flybox0384的指点下,我把数据库更改为

 

数据库pid这一列一级分支pid=no,从二级分支开始,pid=no.Substring(0,2-4-6位了),也就是父节点的no;

下面是代码

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Data.SqlClient;
namespace WindowsFormsApp21
{
    public partial class Form3 : Form
    {
        public Form3()
        {
            InitializeComponent();
        }
        public static readonly string conStr = "Server=PS-12\\SQLEXPRESS;Database=Test_6;Uid=sa;Pwd=0000";

        private void Form3_Load(object sender, EventArgs e)
        {
            try
            {
                TreeNode MarketName = new TreeNode("本店名称");//这个是根节点,这项不允许被删除,为了方便当所有子节点删光后再新增时找不到selectednode
                MarketName.Tag = 0;//根节点的tag不能和表中将要分配的tag重复,重复了子节点追加到根这一行了
                treeView1.Nodes.Add(MarketName);

                SqlConnection con = new SqlConnection(conStr);
                con.Open();
                string sql = "select * from Class_Root";
                SqlCommand com = new SqlCommand(sql, con);
                SqlDataReader dr = com.ExecuteReader();
                while (dr.Read())
                {
                    string rootNo1 = dr["no"].ToString();//这三行分别从数据库中读值
                    string name = dr["name"].ToString();
                    string pid = dr["pid"].ToString();
                    string nodeName = rootNo1 + name;//这行可以不要,我只是为了方便引用
                    int length = rootNo1.Length;//我这里是根据编码no的长度判断是哪一级树节点
                    switch (length)//根据no长度不同做出选择
                    {
                        case 2://no长度2就是一级:01食品
                            TreeNode classname1 = new TreeNode(nodeName);
                            classname1.Tag = rootNo1;//一定要给tag值,不然子节点找不到父节点,如果你的节点名字和待找对象一致就可以不给
                            MarketName.Nodes.Add(classname1);
                            break;

                        case 4://no长度4就是二级:0101饮料
                            TreeNode classname2 = new TreeNode(nodeName);

                            //调用递归FindNode
                            TreeNode tnRet = null;
                            foreach (TreeNode tn in MarketName.Nodes)
                            {
                                tnRet = FindNode(tn, pid);
                                if (tnRet != null)
                                {
                                    classname2.Tag = rootNo1;
                                    tnRet.Nodes.Add(classname2);
                                }
                            }
                            break;

                        case 6://no长度6就是三级:010101碳酸型
                            TreeNode classname3 = new TreeNode(nodeName);

                            //调用递归FindNode
                            TreeNode tnRet2 = null;
                            foreach (TreeNode tn in treeView1.Nodes)
                            {
                                //string FartherNoIsSonPid = rootNo1.Substring(0,4);
                                tnRet2 = FindNode(tn, pid);
                                if (tnRet2 != null)
                                {
                                    classname3.Tag = rootNo1;
                                    tnRet2.Nodes.Add(classname3);
                                }
                            }
                            break;

                        case 8://no长度8就是四级:01010101百事
                            TreeNode classname4 = new TreeNode(nodeName);

                            //调用递归FindNode
                            TreeNode tnRet3 = null;
                            foreach (TreeNode tn in treeView1.Nodes)
                            {
                                //string FartherNoIsSonPid = rootNo1.Substring(0,4);
                                tnRet3 = FindNode(tn, pid);
                                if (tnRet3 != null)
                                {
                                    classname4.Tag = rootNo1;
                                    tnRet3.Nodes.Add(classname4);
                                }
                            }
                            break;

                            //如果还有更多分支可以继续往下分case
                    }

                }
                dr.Close();
                con.Close();
            }
            catch (Exception ex)
            {

                MessageBox.Show(ex.Message);//我为了到看错误直接显示错误,实际用了就不要学我了
            }
            treeView1.ExpandAll();//展开所有节点
        }






        //递归查树节点-------这部分是从网上找的,我根据情况改了一下
        private TreeNode FindNode(TreeNode tnParent, string strValue)//atrValue是tag值
        {
            if (tnParent == null) return null;//非空判断
            //if (tnParent.Text == strValue) return tnParent;//如果目标名称和要传递参数一致就用这行
            if (tnParent.Tag.ToString() == strValue)//我这里改成查找节点tag,因为我的节点名称是no+name连接起来的,直接查名称肯定查不到,tag值才是父节点
                return tnParent;

            TreeNode tnRet = null;
            foreach (TreeNode tn in tnParent.Nodes)//循环查找主函数给到的树tnParent中的节点
            {
                tnRet = FindNode(tn, strValue);//递归到主方法再次取参数
                if (tnRet != null)
                    break;//如果找到则中断
            }
            return tnRet;//最后返回
        }
    }
}

最后效果

分享给和我一样的菜鸟