2012-07-06 89 views
2

我有在C#Node类具有以下属性:递归树生成

public class Node 
{ 
    public int Id {get;set;} 
    public int? ParentId {get;set;} 
    public string Label {get;set;} 
} 

我有一个TreeView控制,其提供了以下的方法来创建 一个新的节点:

MyTreeView.CreateNode(key, label); 
parent.Nodes.CreateNode(key, label); 

如果我想添加一个新的子节点,我需要使用第二种方法,否则使用第一种方法。两者都返回TreeNode类型的对象。

考虑到根节点有ParentId = null,你将如何在C#中创建一个递归函数来填充树视图?

这是我迄今所做的:

// create a list of root nodes 
var roots = myList.Where(x => x.ParentId == null); 
// send the roots to a recursive func 
foreach(var root in roots) 
{ 
    AddNode(null,root,myList); 
} 

这是我的递归函数:

private void AddNode(Node parent, Node current, IList<Node> items) 
{ 
    TreeNode treenode = null; 
    if(parent == null) 
    { 
     treenode = mytree.CreateNode(current.Id.ToString(), current.Label); 
    }else{ 
     var parentnode = mytree.GetNode(parent.Id.ToString()); 
     treenode = parentnode.Nodes.CreateNode(current.Id.ToString(), current.Label); 
    } 
    // call the recursion for the children 
    var children = items.Where(x => x.ParentId == current.Id); 
    foreach(var child in children) 
    { 
     AddNode(current, child, items); 
    } 
} 
+0

您需要添加C#标签。如果这是作业,则还应该添加作业标签。另外,您应该向我们展示您尝试过的代码示例。 – JamieSee 2012-07-06 15:02:45

+0

好的,我会修改帖子,谢谢。 – Raffaeu 2012-07-06 15:03:46

+1

这个功能有什么问题?除了你不需要变量的事实treenode – 2012-07-06 16:32:26

回答

0

如果树视图控件从System.Windows.Forms.TreeView衍生即可更换

MyTreeView.CreateNode(key, label); 
parent.Nodes.CreateNode(key, label); 

MyTreeView.Nodes.Add(key, label); 
parent.Nodes.Add(key, label); 

因此,调用总是进入一个类型为TreeNodeCollection的Nodes集合。您现在可以使用Nodes集合作为参数,而不是Node对象。

var roots = myList.Where(x => x.ParentId == null); 
foreach (var root in roots) 
{ 
    AddNode(mytree.Nodes, root, myList); 
} 

private void AddNode(TreeNodeCollection nodes, Node current, IList<Node> items) 
{ 
    TreeNode treenode = nodes.Add(current.Id.ToString(), current.Label); 

    var children = items.Where(x => x.ParentId == current.Id); 
    foreach (var child in children) 
    { 
     AddNode(treenode.Nodes, child, items); 
    } 
} 

这有两个好处:

  1. 您不必每次查找父。
  2. 您只有一个调用(TreeNodeCollection.Add)。

但是,如果您无法在每个根目录的AddNode调用中访问TreeView.Nodes集合,则必须检查AddNode方法的顶部。

var roots = myList.Where(x => x.ParentId == null); 
foreach (var root in roots) 
{ 
    AddNode(null, root, myList); 
} 

private void AddNode(TreeNodeCollection nodes, Node current, IList<Node> items) 
{ 
    if (nodes == null) 
    { 
     nodes = myTree.Nodes; 
    } 

    ... 
} 
0

试试这个代码:

var lookup = myList.ToLookup(n => n.ParentId.ToString()); 

Action<IEnumerable<TreeNode>> addChildren = null; 
addChildren = tns => 
{ 
    var query = 
     from tn in tns 
     from cn in lookup[tn.Name] 
     select tn.Nodes.CreateNode(cn.Id.ToString(), cn.Label); 
    var nodes = query.ToArray(); 
    if (nodes.Length > 0) 
    { 
     addChildren(nodes); 
    } 
}; 

addChildren(
    lookup[null] 
     .Select(n => 
      MyTreeView.CreateNode(n.Id.ToString(), n.Label))); 

我不能完全测试,所以你可能需要改变一些代码,使其工作,但它应该是相当接近。

0

我可能会做这样的事......

public class Node 
{ 
    public int Id { get; set; } 
    public int? ParentId { get; set; } 
    public string Label { get; set; } 

    public Node(int? parentId, int id, string label) 
    { 
     ParentId = parentId; 
     Id = id; 
     Label = label; 
    } 
} 

public class TreeNode : List<TreeNode> 
{ 
    public string Key { get; set; } 
    public string Label { get; set; } 


    public IEnumerable<TreeNode> Descendants 
    { 
     get 
     { 
      yield return this; 

      foreach (var child in this) 
      { 
       foreach (var descendant in child.Descendants) 
       { 
        yield return descendant; 
       } 

      } 
     } 
    } 

    public TreeNode(string key, string label) 
    { 
     Key = key; 
     Label = label; 
    } 

    public void CreateNode(int id, string label) 
    { 
     Add(new TreeNode(id.ToString(), label)); 
    } 
} 

public class Tree 
{ 
    private TreeNode _root = new TreeNode(null, null); 

    public Tree(IEnumerable<Node> nodes) 
    { 
     nodes.ToList().ForEach(node => CreateNode(node.ParentId, node.Id, node.Label)); 
    } 

    public void CreateNode(int? parentId, int id, string label) 
    { 
     if (parentId == null) 
     { 
      _root.CreateNode(id, label); 
     } 
     else 
     { 
      _root.Descendants.First(x => x.Key == parentId.ToString()).CreateNode(id, label); 
     } 
    } 

    public IEnumerable<TreeNode> Descendants => _root.Descendants; 
}