Рекурсивное добавление узла в a.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, 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 и создания этой древовидной структуры,но я не уверен, как обрабатывать глубину добавления. Я могу добавить первый слой узлов, просто проверив, есть ли у них Родительский код, я могу добавить второй слой узлов в условии 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 } );
}
}
}
}
В настоящее время это не сортировка узлов по рангу
Я ожидал бы, что выходной 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>
3 ответов:
Используйте словарь, чтобы вам не пришлось мучительно сканировать дерево в поисках родителя:
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); }Если ваши данные принимаются в указанном Вами порядке, то выходные данные должны быть неявно в ранговом порядке. Учитывая, что мы всегда добавляем к концу TreeNodeCollections.
Если вы хотите игнорировать любое исключение, в котором родительский узел не найден, но вы все еще хотите присоединить его к корню, внесите следующие изменения:
if(parentID != 0) { TreeNode foundParentNode; //Note: I changed the if logic from, "not TryGetValue" to "TryGetValue" if (ParentCache.TryGetValue(parentID, out foundParentNode) parentNode = foundParentNode.ChildNodes; }
Проверьте это. Это не управляется базой данных, но может помочь вам в построении дерева heirarchical.
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 из отсортированного списка?
Как-то так?
Некоторая структура для хранения ваших данных
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);Метод генерации узлов... просто догадываюсь, чего ты хочешь, так что это не так. полный...
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; }
Comments