C# 递归地将节点添加到.NET树视图中
我需要从数据库表中创建一个菜单结构,该表使用一个ID和一个ParentID以及一个用于确定节点顺序的秩C# 递归地将节点添加到.NET树视图中,c#,.net,treeview,C#,.net,Treeview,我需要从数据库表中创建一个菜单结构,该表使用一个ID和一个ParentID以及一个用于确定节点顺序的秩 Root(ID 1, ParentID 0, Rank 1) - Node(ID 2, ParentID 1, Rank 1) - Node(ID 3, ParentID 2, Rank 1) - Node(ID 4, ParentID 3, Rank 1) - Node(ID 5, ParentID 3, Rank 2) - Node(ID 6,
Root(ID 1, ParentID 0, Rank 1)
- Node(ID 2, ParentID 1, Rank 1)
- Node(ID 3, ParentID 2, Rank 1)
- Node(ID 4, ParentID 3, Rank 1)
- Node(ID 5, ParentID 3, Rank 2)
- Node(ID 6, ParentID 2, Rank 2)
- Node(ID 7, ParentID 2, Rank 3)
- Node(ID 8, ParentID 1, Rank 2)
- Node(ID 9, ParentID 8, Rank 1)
- Node(ID 10, ParentID 8, Rank 2)
我试图创建一个函数来遍历SQL数据并创建此树结构,但我不确定如何处理添加的深度。我可以通过简单地检查第一层节点是否有ParentID来添加第一层节点,我可以在else条件下添加第二层节点,但是我不确定如何添加继承权的以下层
遍历数据库:
using (var command = new SqlCommand(_Query, _Connection))
{
_Connection.Open();
var _Reader = command.ExecuteReader();
while (_Reader.Read())
{
CreateNode((int)_Reader["MenuID"], (int)_Reader["ParentID"], (int)_Reader["Rank"], _Reader["English"].ToString());
}
_Connection.Close();
}
private void CreateNode(int id, int parentID, int rank, string text)
{
if(parentID == -1)
{
TreeNode _Node = new TreeNode(text, id.ToString());
Root.Nodes.Add(_Node);
}
if (parentID != -1)
{
foreach (TreeNode _Node in Root.Nodes)
{
if (_Node.Value == parentID.ToString())
{
_Node.ChildNodes.Add(new TreeNode(text, id.ToString()) { ShowCheckBox = true } );
}
}
}
}
节点的创建:
using (var command = new SqlCommand(_Query, _Connection))
{
_Connection.Open();
var _Reader = command.ExecuteReader();
while (_Reader.Read())
{
CreateNode((int)_Reader["MenuID"], (int)_Reader["ParentID"], (int)_Reader["Rank"], _Reader["English"].ToString());
}
_Connection.Close();
}
private void CreateNode(int id, int parentID, int rank, string text)
{
if(parentID == -1)
{
TreeNode _Node = new TreeNode(text, id.ToString());
Root.Nodes.Add(_Node);
}
if (parentID != -1)
{
foreach (TreeNode _Node in Root.Nodes)
{
if (_Node.Value == parentID.ToString())
{
_Node.ChildNodes.Add(new TreeNode(text, id.ToString()) { ShowCheckBox = true } );
}
}
}
}
目前这不是按等级对节点进行排序
我希望输出的HTML类似于以下内容:
<ul id="1">
<li>A</li>
<li>
<ul id="2">
<li>B</li>
<li>
<ul id="3">
<li>C</li>
<li>
<ul id="4">
<li>D</li>
</ul>
</li>
<li>
<ul id="5">
<li>E</li>
</ul>
</li>
</ul>
</li>
<li>
<ul id="6">
<li>F</li>
</ul>
</li>
<li>
<ul id="7">
<li>G</li>
</ul>
</li>
</ul>
</li>
<li>
<ul id="8">
<li>H</li>
<ul>
<li>
<ul id="9">
<li>I</li>
</ul>
</li>
<li>
<ul id="10">
<li>J</li>
</ul>
</li>
</ul>
</ul>
</li>
</ul>
- A
-
- B
-
- C
-
- D
-
- E
-
- F
-
- G
-
- H
-
- 我
-
- J
看看这个。这不是数据库驱动的,但可能有助于您构建继承人体系结构树
TreeView tv = new TreeView();
private void populateNode()
{
for(int i=0;i<5;i++)
{
var parent = new TreeNode(i,string.Format("Node{0}",i));
tv.Nodes.Add(parent);
for(int j=0;j<=3;j++)
{
var child = new TreeNode(j,string.Format("childNode{0}",j)
parent.ChildNodes.Add(child);
for(int k=0;k<=3;k++)
{
var grandchild = new TreeNode(k,string.Format("grandchildNode{0}",k)
child.ChildNodes.Add(grandchild);
}
}
}
}
TreeView tv=new TreeView();
私有void populateNode()
{
对于(inti=0;i你不能简单点吗
- 创建一些自定义对象的列表,其中包含从数据库数据(在读卡器循环中)中需要的所有属性
- 按秩属性对列表排序
- 从排序列表填充树视图
像这样
一些用于存储数据的结构
class TempTreeNode
{
public int MenuID { get; set; }
public int ParentID { get; set; }
public int Rank { get; set; }
public string Lang { get; set; }
}
生成列表的代码:
var nodeList = new List<TempTreeNode>();
using (var command = new SqlCommand(_Query, _Connection))
{
_Connection.Open();
var _Reader = command.ExecuteReader();
while (_Reader.Read())
{
var node = new TempTreeNode()
{
MenuID = (int)_Reader["MenuID"],
ParentID = (int)_Reader["ParentID"],
Rank = (int)_Reader["Rank"],
Lang = _Reader["English"].ToString()
};
nodeList.Add(node);
}
_Connection.Close();
}
// sorting
nodeList.Sort((a, b) => a.Rank.CompareTo(b.Rank));
// creation
CreateNodes(nodeList);
var nodeList=new List();
使用(var命令=新的SqlCommand(_查询,_连接))
{
_Connection.Open();
var_Reader=command.ExecuteReader();
而(_Reader.Read())
{
var node=new testreenode()
{
MenuID=(int)\读卡器[“MenuID”],
ParentID=(int)u读取器[“ParentID”],
秩=(int)_读取器[“秩”],
Lang=_Reader[“English”]。ToString()
};
nodeList.Add(节点);
}
_Connection.Close();
}
//分类
节点列表排序((a,b)=>a.Rank.CompareTo(b.Rank));
//创作
创建节点(节点列表);
生成节点的方法…只是猜测你想要什么,所以这是不完整的
private List<TreeNode> CreateNodes(List<TempTreeNode> nodes)
{
var rootNodes = new List<TreeNode>();
foreach (var node in nodes)
{
if (node.ParentID == -1)
{
TreeNode _Node = new TreeNode(node.Lang, node.MenuID.ToString());
rootNodes.Add(_Node);
}
[...] do whatever...
}
return rootNodes;
}
私有列表创建节点(列表节点)
{
var rootNodes=新列表();
foreach(节点中的var节点)
{
if(node.ParentID==-1)
{
TreeNode_Node=新的TreeNode(Node.Lang,Node.MenuID.ToString());
添加(_节点);
}
[…]做任何事。。。
}
返回根节点;
}
使用字典,这样您就不必费力地在树中查找父目录:
Dictionary<int, TreeNode> ParentCache = new Dictionary<int, TreeNode>();
private void CreateNode(int id, int parentID, int rank, string text)
{
TreeNodeCollection parentNode = root.Nodes;
if(parentID != 0)
{
TreeNode foundParentNode;
if (!ParentCache.TryGetValue(parentID, out foundParentNode)
throw new Exception("Given parentID has not been added to the tree yet - " + parentID.ToString());
parentNode = foundParentNode.ChildNodes;
}
TreeNode newNode = new TreeNode(text, id.ToString());
parentNode.Add(newNode);
ParentCache.Add(id, newNode);
}
用一些示例代码更新了我的答案,如果您需要进一步解释,请告诉我谢谢,我用您的代码想出了一个解决方案。只需对缓存做一个小的更改,即检查字典中是否存在parentid键(否则会出错).@Jack-I更新为包含TryGetValue模式以获取更多描述性错误消息。感谢@Todd我使用了:ParentCache.Keys.Contains(parentID)。我想没有太大区别。没有父节点没关系,所以我没有添加异常,因为它应该只将其添加到根节点。@Jack,如果不希望出现异常,可以用返回替换抛出。TryGetValue模式只枚举字典一次。如果使用Contains,还需要查找up值-两次查找,这不一定是一个明显的性能问题。在您的情况下,我建议查找不匹配应该是一个例外。在这种例外情况下,源数据出错,需要更正数据或查询。