2009-09-03 2 views
8

У меня есть TreeView Управление с набором узлов и дочерних узлов. Например:Доступ ко всем узлам в элементе управления TreeView

ROOT имеет A, B, C.

A имеет a1, a2, a3, а затем a1, a2 также содержит некоторые узлы, такие как x1, x2, x3 и т. Д. Подобно этому много подносов. Я знаю, что можно использовать циклы с циклом for.

Я просто хочу получить доступ ко всем узлам в TreeView, используя один или два для циклов.

Есть ли какой-либо алгоритм для этого или есть ли другой способ?

Еще один вопрос: возможно ли иметь путь к узлу дерева в объекте или в строке с использованием любых функций библиотеки? Например:

string S = TreeView1.Nodes[i].Nodes[j].Nodes 

ответ

9

Не использовать вложенные циклы, но идти на рекурсивное решение, как:

void ListNodes(TreeNode node) 
{ 
    foreach(var subnode in node.Nodes) 
    { 
    ListNodes(subnode); 
    } 
    // Print out node 
} 

этой функцию для корневого узла Call.

За дополнительной информацией обращайтесь: FullPath.

5

Вы можете использовать рекурсивную функцию для обхода всего дерева:

private void Traverse(TreeNodeCollection nodes) 
{ 
    foreach (TreeNode node in nodes) 
    { 
     Console.WriteLine("{0} -> {1}", node.Name, node.FullPath); 
     Traverse(node.Nodes); 
    } 
} 

Вы можете назвать это с помощью:

Traverse(treeView.Nodes); 

, и он будет ходить всю глубину дерева первого (т.е. происходит. как можно глубже, прежде чем переходить к следующему брату). Передача в коллекции Nodes означает, что этот код будет иметь дело с деревьями с несколькими корневыми узлами.

В приведенном выше примере кода будет напечатано имя узла, а также полный путь этого узла в дереве.

5

Я не самый большой поклонник рекурсии, но, похоже, вы должны использовать его. Я видел умный пример онлайн-рекурсии смешивания с итератором.

private int GetLevels(TreeNodeCollection treeNodes) 
    { 
     int level = 0; 
     foreach (TreeNode node in TreeTopDown(treeNodes)) 
     { 
      int i = node.Level; 
      if (i > level) level = i; 
     } 
     return level; 
    } 

    //TopDown Iterator 
    private IEnumerable<TreeNode> TreeTopDown(TreeNodeCollection treeNodes) 
    { 
     foreach (TreeNode node in treeNodes) 
     { 
      yield return node; 
      foreach (TreeNode subNode in TreeTopDown(node.Nodes)) yield return subNode;    
     } 
    } 

    //BottomUp Iterator 
    private IEnumerable<TreeNode> TreeBottomUp(TreeNodeCollection treeNodes) 
    { 
     foreach (TreeNode node in treeNodes) 
     { 
      foreach (TreeNode subNode in TreeBottomUp(node.Nodes)) yield return subNode; 
      yield return node; 
     } 
    } 
1

Вы можете использовать очереди как то, что я сделал в моем приложении:

List<TreeNode> nodes = new List<TreeNode>(); 
Queue<TreeNode> queue = new Queue<TreeNode>(); 

// 
// first insert all the root nodes into the queue. 
// 
foreach(TreeNode root in tree.Nodes) { 
    queue.Enqueue(root); 
} 

while(queue.Count > 0) { 
    TreeNode node = queue.Dequeue(); 
    if(node != null) { 
     // 
     // Add the node to the list of nodes. 
     // 
     nodes.Add(node); 

     if(node.Nodes != null && node.Nodes.Count > 0) { 
      // 
      // Enqueue the child nodes. 
      // 
      foreach(TreeNode child in node.Nodes) { 
       queue.Enqueue(child); 
      } 
     } 
    } 
} 
2

Я знаю, что эта нить довольно старая и мой метод не точно уменьшить количество рекурсии и его по может быть немного медленнее, но это делает мой код немного чище.

Я использую метод расширения для IEnumarable<> выравниваться любого дерева (а не только TreeView узлы):

public static IEnumerable<T> Flatten<T>(
    this IEnumerable<T> rootNodes, 
    Func<T, IEnumerable<T>> childrenFunction) 
{ 
    return rootNodes.SelectMany(
     child => new[] { child } 
      .Concat((childrenFunction(child) ?? Enumerable.Empty<T>()) 
      .Flatten(childrenFunction))); 
} 

я затем использовать этот метод, чтобы получить все узлы дерева:

IEnumerable<TreeNode> allNodes = treeView1.Nodes.Cast<TreeNode>() 
    .Flatten<TreeNode>(n => n.Nodes.Cast<TreeNode>()); 
+0

это выглядит очень аккуратно ... Может ли он быть преобразован в VB.NET? Может ли VB использовать оператор =>? – Grantly

3

Вы можете создать метод расширения, который возвращает List<TreeNode>.

Наследники метод расширения

using System.Linq; 
using System.Windows.Forms; 
using System.Collections.Generic; 

public static class Extensions 
{ 
    public static List<TreeNode> Descendants(this TreeView tree) 
    { 
     var nodes = tree.Nodes.Cast<TreeNode>(); 
     return nodes.SelectMany(x => x.Descendants()).Concat(nodes).ToList(); 
    } 

    public static List<TreeNode> Descendants(this TreeNode node) 
    { 
     var nodes = node.Nodes.Cast<TreeNode>().ToList(); 
     return nodes.SelectMany(x => Descendants(x)).Concat(nodes).ToList(); 
    } 
} 

Чтобы получить все узлы в TreeView

var nodes = this.treeView1.Descendants(); 

Для получения всех дочерних узлов узла

var nodes = this.treeView1.Nodes[0].Descendants(); 

Вы также можете использовать LINQ для поиска между узлами.

0

Следующий код используется для обхода узлов TreeView и возвращаемся только листовые узлы:

private IEnumerable<TreeNode> LeafNodes(TreeNode root) 
{ 
    Stack<TreeNode> stack = new Stack<TreeNode>(); 
    stack.Push(root); 
    while (stack.Count > 0) 
    { 
     TreeNode current = stack.Pop(); 
     if (current.Nodes.Count == 0) 
     { 
      yield return current; 
     } 
     else 
     { 
      foreach (TreeNode child in current.Nodes) 
      { 
       stack.Push(child); 
      } 
     } 
    } 
} 

я использую его для доступа к имени файла в проводнике, как TreeView:

private void LogFileNames() 
{ 
    //There may be more than one node at root level 
    foreach (TreeNode rootNode in FileTreeView.Nodes) 
    { 
     //Print only filenames, not directories 
     foreach (TreeNode leafNode in LeafNodes(rootNode)) 
     { 
      Logger.Info(leafNode.Text); 
     } 
    } 
} 
Смежные вопросы