2009-09-03 3 views
8

Tôi có một điều khiển TreeView với bộ nút và nút con. Ví dụ:Truy cập tất cả các nút trong Điều khiển TreeView

ROOT có A, B, C.

A có a1, a2, a3 và sau đó a1, a2 cũng chứa một số nút như x1, x2, x3, v.v. Giống như nhiều subnodes này. Tôi biết có thể sử dụng vòng lặp với vòng lặp for.

Tôi chỉ muốn truy cập tất cả các nút trong điều khiển TreeView bằng một hoặc hai nút cho vòng lặp.

Có bất kỳ thuật toán nào cho điều đó hoặc có cách nào khác không?

Một câu hỏi nữa: Có thể có đường dẫn của nút cây trong đối tượng hoặc trong chuỗi bằng bất kỳ chức năng thư viện nào không? Ví dụ:

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

Trả lời

9

Không sử dụng các vòng lặp lồng nhau, nhưng đi cho một giải pháp đệ quy như:

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

Gọi chức năng này cho nút gốc của bạn.

Đối với câu hỏi bổ sung của bạn: hãy kiểm tra thuộc tính FullPath.

5

Bạn có thể sử dụng một hàm đệ quy để đi qua toàn bộ cây:

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

Sau đó, bạn có thể gọi đây là cách sử dụng:

Traverse(treeView.Nodes); 

và nó sẽ đi sâu cây toàn đầu tiên (tức là đi. xuống sâu như nó có thể trước khi chuyển sang anh chị em tiếp theo). Đi qua trong bộ sưu tập Nodes có nghĩa là mã này sẽ xử lý các cây có nhiều nút gốc.

Mã ví dụ ở trên sẽ in ra tên của nút cũng như đường dẫn đầy đủ của nút đó trong cây.

5

Tôi không phải là fan hâm mộ lớn nhất của đệ quy nhưng có vẻ như bạn phải sử dụng nó. Tôi thấy một ví dụ thông minh trộn trực tuyến đệ quy với một iterator.

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

Bạn có thể sử dụng Queue như những gì tôi đã làm trong ứng dụng của tôi:

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

Tôi biết chủ đề này là khá cũ và phương pháp của tôi không chính xác làm giảm lượng đệ quy nó có thể hơi chậm nhưng nó làm cho mã của tôi sạch hơn một chút.

tôi sử dụng một phương pháp mở rộng cho IEnumarable<> để san bằng bất kỳ cây (không chỉ các nút 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))); 
} 

sau đó tôi sử dụng phương pháp này để có được tất cả các nút của cây:

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

vẻ này rất gọn gàng ... Nó có thể được chuyển đổi sang VB.NET không? VB có thể sử dụng toán tử => không? – Grantly

3

Bạn có thể tạo phương thức tiện ích mở rộng trả về List<TreeNode>.

Descendants Phương pháp mở rộng

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(); 
    } 
} 

Để có được tất cả các nút của một TreeView

var nodes = this.treeView1.Descendants(); 

Để có được tất cả các nút con của một Node

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

Bạn cũng có thể sử dụng LINQ để tìm kiếm giữa các nút.

0

Các mã sau đây được sử dụng để vượt qua các nút của một TreeView và chỉ trả lại các nút lá:

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); 
      } 
     } 
    } 
} 

tôi sử dụng nó để truy cập vào tên tập tin trong một nhà thám hiểm như 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); 
     } 
    } 
}