c# treeview 类别树 存入数据库并读取出来

c# treeview 类别树 存入数据库并读取出来,第1张

递归法生成树,给你一个我做的生成公司组织结构方法参考一下吧。
#region 加载所有部门树形
/// <summary>
/// 根据用户ID加载对应的菜单
/// </summary>
/// <param name="userId"></param>
public static void DisplayDemparmnetsTree(TreeView tree)
{
treeNodesClear();
IList<DepartmentInfo> list = DepartmentInfoManagerGetDepartmentInfosByFatherId("0");
foreach (DepartmentInfo dep in list)
{
TreeNode fathernode = CreatTreeNode(depDepartmentName, depDepartmentIdToString(), "", "~/Images/menuclosegif");
treeNodesAdd(fathernode);
CreateChildTree(depDepartmentIdToString(), fathernode);
}
}
private static TreeNode CreatTreeNode(string strText, string strId, string strUrl, string strImg)
{
TreeNode newNode = new TreeNode();
newNodeText = strText;
newNodeValue = strId;
newNodeNavigateUrl = strUrl;
newNodeImageUrl = strImg;
return newNode;
}
private static void CreateChildTree(string fatherDepartmentId, TreeNode fatherNode)
{
IList<DepartmentInfo> childlist = DepartmentInfoManagerGetDepartmentInfosByFatherId(fatherDepartmentId);
foreach (DepartmentInfo dep in childlist)
{
TreeNode childNode = CreatTreeNode(depDepartmentName, depDepartmentIdToString(), "", "~/Images/menuclosegif");
fatherNodeChildNodesAdd(childNode);
CreateChildTree(depDepartmentIdToString(), childNode);
}
}
#endregion

树状结构的数据保存在数据库中的常用方法有一下两种:
1、邻接表(adjacency list model)
2、预排序遍历树算法(modified preorder tree traversal algorithm)
用一下的例子讨论这两种方法的差异:
现有一棵树如下:
邻接表模式:
这种模式我们经常用到,很多的教程和书中也介绍过。我们通过给每个节点增加一个属性 parent 来表示这个节点的父节点从而将整个树状结构通过平面的表描述出来。根据这个原则,例子中的数据可以转化成如下的表:
我们看到 Pear 是Green的一个子节点,Green是Fruit的一个子节点。而根节点'Food'没有父节点。 为了简单地描述这个问题, 这个例子中只用了name来表示一个记录。 在实际的数据库中,你需要用数字的id来标示每个节点,数据库的表结构大概应该像这样:id, parent_id, name, description。
以下是代码:
<php
// $parent is the parent of the children we want to see
// $level is increased when we go deeper into the tree,
// used to display a nice indented tree

function display_children($parent, $level)
{
// 获得一个 父节点 $parent 的所有子节点
$result = mysql_query('SELECT name FROM tree '
'WHERE parent="'$parent'";');

// 显示每个子节点
while ($row = mysql_fetch_array($result))
{
// 缩进显示节点名称
echo str_repeat(' ',$level)$row['name']"n";

//再次调用这个函数显示子节点的子节点

display_children($row['name'], $level+1);
}
}
>
对整个结构的根节点(Food)使用这个函数就可以打印出整个多级树结构,由于Food是根节点它的父节点是空的,所以这样调用: display_children('',0)。将显示整个树的内容:
Food
Fruit
Red
Cherry
Yellow
Banana
Meat
Beef
Pork
如果你只想显示整个结构中的一部分,比如说水果部分,就可以这样调用:display_children('Fruit',0);
几乎使用同样的方法我们可以知道从根节点到任意节点的路径。比如 Cherry 的路径是 "Food >; Fruit >; Red"。 为了得到这样的一个路径我们需要从最深的一级"Cherry"开始, 查询得到它的父节点"Red"把它添加到路径中, 然后我们再查询Red的父节点并把它也添加到路径中,以此类推直到最高层的"Food"
以下是代码:

<php
// $node 是那个最深的节点
function get_path($node)
{
// 查询这个节点的父节点
$result = mysql_query('SELECT parent FROM tree '
'WHERE name="'$node'";');
$row = mysql_fetch_array($result);

// 用一个数组保存路径
$path = array();

// 如果不是根节点则继续向上查询
// (根节点没有父节点)
if ($row['parent']!='')
{
// the last part of the path to $node, is the name
// of the parent of $node
$path[] = $row['parent'];

// we should add the path to the parent of this node
// to the path
$path = array_merge(get_path($row['parent']), $path);
}

// return the path
return $path;
}
>
如果对"Cherry"使用这个函数:print_r(get_path('Cherry')),就会得到这样的一个数组了:
Array
(
[0] =>; Food
[1] =>; Fruit
[2] =>; Red
)
接下来如何把它打印成你希望的格式,就是你的事情了。
缺点:
这种方法很简单,容易理解,好上手。但是也有一些缺点。主要是因为运行速度很慢,由于得到每个节点都需要进行数据库查询,数据量大的时候要进行很多查询才能完成一个树。另外由于要进行递归运算,递归的每一级都需要占用一些内存所以在空间利用上效率也比较低。
预排序遍历树算法
现在让我们看一看另外一种不使用递归计算,更加快速的方法,这就是预排序遍历树算法(modified preorder tree traversal algorithm) 这种方法大家可能接触的比较少,初次使用也不像上面的方法容易理解,但是由于这种方法不使用递归查询算法,有更高的查询效率。
我们首先将多级数据按照下面的方式画在纸上,在根节点Food的左侧写上 1 然后沿着这个树继续向下 在 Fruit 的左侧写上 2 然后继续前进,沿着整个树的边缘给每一个节点都标上左侧和右侧的数字。最后一个数字是标在Food 右侧的 18。 在下面的这张图中你可以看到整个标好了数字的多级结构。(没有看懂?用你的手指指着数字从1数到18就明白怎么回事了。还不明白,再数一遍,注意移动你的手指)。
这些数字标明了各个节点之间的关系,"Red"的号是3和6,它是 "Food" 1-18 的子孙节点。 同样,我们可以看到 所有左值大于2和右值小于11的节点 都是"Fruit" 2-11 的子孙节点
这样整个树状结构可以通过左右值来存储到数据库中。继续之前,我们看一看下面整理过的数据表。
注意:由于"left"和"right"在 SQL中有特殊的意义,所以我们需要用"lft"和"rgt"来表示左右字段。 另外这种结构中不再需要"parent"字段来表示树状结构。也就是 说下面这样的表结构就足够了。
SELECT FROM tree WHERE lft BETWEEN 2 AND 11;
看到了吧,只要一个查询就可以得到所有这些节点。为了能够像上面的递归函数那样显示整个树状结构,我们还需要对这样的查询进行排序。用节点的左值进行排序:
SELECT FROM tree WHERE lft BETWEEN 2 AND 11 ORDER BY lft ASC;

private DataSet ds;
private SqlDataAdapter sqlDataAdapter1;
private int maxnodeid;

private void Form1_Load(object sender, SystemEventArgs e)
{
string strconn=ConfigurationSettingsAppSettings["ConnStr"];
sqlConnection1 = new SqlConnection(strconn);
thissqlConnection1Open();
//填充DataSet
thisCreateDataSet();
//从数据库中读取数据,通过递归生成树。
InitTree(thistreeView1Nodes,"0");

}
private void CreateDataSet()
{
thissqlDataAdapter1=new SqlDataAdapter("select from s_menu ",thissqlConnection1);
thisds=new DataSet();
thissqlDataAdapter1Fill(ds,"tree");
}
private void InitTree(TreeNodeCollection Nds,string parentId)
{
DataView dv=new DataView();
TreeNode tmpNd;
string intId;
dvTable=dsTables["tree"];
dvRowFilter="ParentId='" + parentId + "'" ;
foreach(DataRowView drv in dv)
{
tmpNd=new TreeNode();
tmpNdTag=drv["NodeId"]ToString();
tmpNdText=drv["NodeName"]ToString();
NdsAdd(tmpNd);
intId=drv["ParentId"]ToString();
InitTree(tmpNdNodes,tmpNdTagToString());
}
}
//新增节点 *** 作
private void insert(string type)
{//判断是新增树节点,还是子节点
string strinsert="insert into s_menu values('{0}','{1}','{2}')";
string strformat="";
if(type=="sub")
strformat=stringFormat(strinsert,maxnodeidToString(),thisselectnodeTagToString(),thisstrcomm);
else
strformat=stringFormat(strinsert,maxnodeidToString(),"0",thisstrcomm);
SqlCommand cmd=new SqlCommand(strformat,thissqlConnection1);
cmdExecuteNonQuery();
}
//为新增节点算出最大的节点值,并以此值作为新增的节点ID值
private int GetMaxNodeid()
{
int pre=0,last=0;
DataSet maxds=new DataSet();
thissqlDataAdapter1=new SqlDataAdapter("select nodeid from s_menu order by nodeid",thissqlConnection1);
thissqlDataAdapter1Fill(maxds);
for(int i=0;i{
if(i+1{
pre=intParse(maxdsTables[0]Rows[i][0]ToString());
last=intParse(maxdsTables[0]Rows[i+1][0]ToString());
if(last-pre!=1)
return pre+1;
}
}
return last+1;
}
private void getallnode(TreeNode tn)
{
foreach(TreeNode node in tnNodes)
{
listAdd(nodeTagToString());
if(nodeNodesCount>0)
{
getallnode(node);
}
}
}

private void treeView1_MouseDown(object sender, SystemWindowsFormsMouseEventArgs e)
{
//判断是否点击了某个节点
thisselectnode= thistreeView1GetNodeAt (eX ,eY );
if(selectnode==null)
thisisselected=false;
else
thisisselected=true;
}
private void menuAdd_Click(object sender, SystemEventArgs e)
{//判断是否点击了某个节点,若没有点击了,则是新增一个树节点
if(isselected==false)
{//算出新增树节点的ID值
maxnodeid=GetMaxNodeid();
TreeNode tmpNd=new TreeNode();
//赋值
tmpNdTag=thismaxnodeidToString();
FormCommon frmCommon=new FormCommon();
DialogResult result= frmCommonShowDialog();
if(result==DialogResultOK)
{//取到新增树节点的文本值
tmpNdText=frmCommonstrcomm;
thisstrcomm=frmCommonstrcomm;
//新增树节点
thistreeView1NodesAdd(tmpNd);
//插入数据库(说明插入的是树节点)
thisinsert("root");
//展开
thisselectnodeExpand();
}
}
else
{//判断是否点击了某个节点,若点击了,则是新增一个子节点
thiscontextAddSub();
}
}
private void contextAddSub()
{//得到新增子节点的ID值
maxnodeid=GetMaxNodeid();
TreeNode tmpNd=new TreeNode();
//赋值
tmpNdTag=thismaxnodeidToString();
FormCommon frmCommon=new FormCommon();
DialogResult result= frmCommonShowDialog();
if(result==DialogResultOK)
{//取到新增树节点的文本值
tmpNdText=frmCommonstrcomm;
thisstrcomm=frmCommonstrcomm;
//新增子节点
thisselectnodeNodesAdd(tmpNd);
//插入数据库(说明插入的是子节点)
thisinsert("sub");
//展开
thistreeView1SelectedNodeExpand();
}
}
//删除节点 *** 作
private void menuDel_Click(object sender, SystemEventArgs e)
{//新建一个ArrayList,用于保存要删除的节点下边的所有子节点
list=new ArrayList();
if(thisisselected==true)
{//得到删除的节点下边的所有子节点
getallnode(thisselectnode);
//把要删除的节点也加进去
listAdd(thisselectnodeTagToString());
//循环从数据库中删除
for(int i=0;i{
string strdel="delete s_menu where nodeid='{0}'";
string strformat="";
strformat=stringFormat(strdel,list[i]);
SqlCommand cmd=new SqlCommand(strformat,thissqlConnection1);
cmdExecuteNonQuery();
}
//从树中删除
thisselectnodeRemove();
}
}
//修改节点的值
private void menuEdit_Click(object sender, SystemEventArgs e)
{
if(thisisselected==true)
{
FormCommon frmCommon=new FormCommon();
DialogResult result= frmCommonShowDialog();
if(result==DialogResultOK)
{
string strdel="update s_menu set nodename= '{1}' where nodeid='{0}'";
string strformat="";
strformat=stringFormat(strdel,thisselectnodeTagToString(),frmCommonstrcomm);
SqlCommand cmd=new SqlCommand(strformat,thissqlConnection1);
cmdExecuteNonQuery();
thisselectnodeText=frmCommonstrcomm;
}
}
}
//遍历所有节点查找值
private void getvaluenode(TreeNodeCollection tn,string value)
{
foreach(TreeNode node in tn)
{
if(nodeNodesCount>0)
{
getvaluenode(nodeNodes,value);
}
if(nodeText==value)
listnodeAdd(node);
}
}
private void menuSearch_Click(object sender, SystemEventArgs e)
{
int j,k;
thislistnode=new ArrayList();
FormCommon frmCommon=new FormCommon();
DialogResult result= frmCommonShowDialog();
if(result==DialogResultOK)
{
TreeNode n =new TreeNode();
TreeNode temp=new TreeNode();
//下面的函数是填充listnode;
getvaluenode(thistreeView1Nodes,frmCommonstrcomm);
for(int i=0;i{
j=0;k=0;
n=(TreeNode)listnode[i];
if (n != null)
{
temp=n;
//得到上面结点的数量,并将数量保存到变量j;
for(;nParent!=null;)
{
n=nParent;
j++;
}
//恢复原值
n=temp;
//新建一个树结点数组做保存得到查询到的所有节点
TreeNode[] m=new TreeNode[j];
for(;nParent!=null;)
{
n=nParent;
m[k]=n;
k++;
}
for(int p=0;pm[p]Expand();
n=temp;
nForeColor=ColorRed;
}
}
}
}
private void treeView1_AfterLabelEdit(object sender, SystemWindowsFormsNodeLabelEditEventArgs e)
{
if(thistreeView1SelectedNodeText!=null)
{
string strdel="update s_menu set nodename= '{1}' where nodeid='{0}'";
string strformat="";strformat=stringFormat(strdel,thistreeView1SelectedNodeTagToString(),eLabelToString());SqlCommand cmd=new SqlCommand(strformat,thissqlConnection1);
cmdExecuteNonQuery();

}
}
private void treeView1_AfterSelect(object sender, SystemWindowsFormsTreeViewEventArgs e)
{
thislistBox1ItemsClear();
thislistBox1ItemsAdd(thistreeView1SelectedNodeFullPathToString());
}
}
}

树型结构数据在数据库中常见的表现方式有两种:
1 层级代码
2 存储父ID
例如:
1:
create table tb_menu (
code varchar(32), name varchar(32)
)
insert into tb_menu ('01','File')
insert into tb_menu ('02','Edit')
insert into tb_menu ('03','Tool')
insert into tb_menu ('04','Help')
insert into tb_menu('0101','Open')
insert into tb_menu('0102','Close')
insert into tb_menu('0103','New')
insert into tb_menu('0104','Save')
insert into tb_menu('0201','Undo')
insert into tb_menu('0202','Redo')
insert into tb_menu('0203','Copy')
insert into tb_menu('0204','Cut')
insert into tb_menu('0205','Paste')
insert into tb_menu('0301','Option')
insert into tb_menu('0302','Extend')
2:
create table tb_menu (
id int, name varchar(32), parentid int
)
insert into tb_menu (1,'File', 0)
insert into tb_menu (2,'Edit',0)
insert into tb_menu (3,'Tool',0)
insert into tb_menu (4,'Help',0)
insert into tb_menu(5,'Open',1)
insert into tb_menu(6,'Close',1)
insert into tb_menu(7,'New',1)
insert into tb_menu(8,'Save',1)
insert into tb_menu(9,'Undo',2)
insert into tb_menu(10,'Redo',2)
insert into tb_menu(11,'Copy',2)
insert into tb_menu(12,'Cut',2)
insert into tb_menu(13,'Paste',2)
insert into tb_menu(14,'Option',3)
insert into tb_menu(15,'Extend',3)

以前用dtree写过一个,先把你数据库数据查出来,重点是确定父id跟子id都已经分好了,然后剩下的主要是在jsp里写树菜单就好了:给你参考下,下面那两个文件你可能没有,不过应该可以在网上下载的

<div class="dtree">

<p><a href="javascript: dopenAll();">展开</a> | <a href="javascript: dcloseAll();">关闭</a></p>

<script type="text/javascript">

d = new dTree('d',"${contextPath}/js/dtree/");

dadd(0,-1,'涉及问题选择');

<c:forEach items="${problemList}" var="pro">

var fid;

var config="${procontent}";

fid = '${profid}';

var id = '${proid}';

if(${proson}==0){

ss='+config,'${procontent}','frame_right');

dadd('${proid}',fid,config,'${contextPath}/ajdj/ajdj_sjwtLjdoconfigid='+id,'${procontent}','frame_right');

}else{

dadd('${proid}',fid,config,'','${procontent}','frame_right');

}

</c:forEach>

documentwrite(d);

</script>

</div>

aspnetmvc5实现打开树形结构链接后保持树形结构将树形目录的节点存入数据库,为我们动态形成树形目录打下良好的基础。当然,也有些目录树是表现一个数据库中的数据结构父节点是数据库名,子节点是数据表。不管如何,有了前面的基础,现在我们所需做的只是将数据库的内容形成上面格式的文档。

如果采用父子节点的方式 效率上可能不高 但容易实现
也可以采用如下的方式
000
000000
000001
000002
000000001
这样三位表示一级 但是对每级的节点数有限制 查询也很容易
表示层次的可以快速方便的查询


欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/yw/13392148.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-07-27
下一篇 2023-07-27

发表评论

登录后才能评论

评论列表(0条)

保存