各位大大们好,我是才学一个月的新手,这个问题研究一天了,搞不定,查了好多资料也没搞定.
数据库是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;//最后返回
}
}
}
最后效果
分享给和我一样的菜鸟