从列表中填充TreeView,没有子节点,其子节点不会有子节点

时间:2014-04-03 11:30:36

标签: c# winforms list treeview children

使用.NET 4 WinForms 我们假设我们的课程定义为:

public class Item
{
    public int ID { get; set; }
    public int Key { get; set; }
    public int Value { get; set; }
}

和一个清单:

List<Item> items;

包含以下内容:

Key    Value
---    -----
 1       1
 1       2
 1       3
 4       4
 4       5
 2       6
 2       7
 7       8

我从此列表中填充TreeView,以便根树节点是具有相同键和值的节点。我就是这样做的:

var roots = items.Where(x => x.Key == x.Value);
foreach (var root in roots)
{
    AddNode(treeView1.Nodes, root, items);
}

AddNode函数是一个如下定义的递归函数:

void AddNode(TreeNodeCollection nodes, Item current, IList<Item> items)
    {
        TreeNode treenode = nodes.Add(current.Value.ToString(), current.Value.ToString());

        var children = items.Where(x => x.Key == current.Value && x.ID != current.ID);
        foreach (var child in children)
        {
            AddNode(treenode.Nodes, child, items);
        }
    }

这将产生以下TreeView结构:

_1
 |_2
 | |_6
 | |_7
 |   |_8
 |
 |_3

_4
 |_5

但是,我想要的是创建一个结构,该结构仅包含至少有一个子节点的根节点,该子节点至少有一个子节点拥有它。在这种情况下,具有值&#34; 1&#34;的根项目有一个有价值的孩子&#34; 2&#34;这又有至少一个孩子。根值&#34; 4&#34;有一个有价值的孩子&#34; 5&#34;但那个孩子没有孩子所以我想省略它。生成的TreeView将如下所示:

_1
 |_2
 | |_6
 | |_7
 |   |_8
 |
 |_3

为了进一步澄清,这是我用来清理TreeView后填充的代码:

List<TreeNode> ToRemove = new List<TreeNode>();
foreach (TreeNode n in treeView1.Nodes)
{
    if (n.Nodes.Count == 0)
        ToRemove.Add(n);
    else if (!n.Nodes.Cast<TreeNode>().Any(x => x.Nodes.Count > 0))
        ToRemove.Add(n);
}
ToRemove.ForEach(x => treeView1.Nodes.Remove(x)));

如何在填充TreeView之前执行此类清理?

修改

根据Aaron的建议,我修改了这样的代码:

var roots = items.Where(x => x.Key == x.Value);
foreach (var root in roots)
{
    Add2ndLevelNode(treeView1.Nodes, root, items);
}

功能&#34; Add2ndLevelNode&#34;看起来像这样:

    void Add2ndLevelNode(TreeNodeCollection nodes, Item current, IList<Item> items)
    {
        var children = items.Where(x => x.Key == current.Value && x.ID != current.ID);
        bool doIt = false;
        foreach (var child in children)
        {
            if (items.Any(x => x.Key == child.Value))
                doIt = true;
        }
        if (doIt)
        {
            TreeNode treenode = nodes.Add(current.Value.ToString(), current.Value.ToString());

            foreach (var child in children)
            {
                AddNode(treenode.Nodes, child, items);
            }
        }
    }

还有其他更优雅的方式吗?这样,它需要对孩子们进行两次for-each循环。

2 个答案:

答案 0 :(得分:1)

如果孩子的数量超过1,那么在进入第二级之前检查,这个片段是原始的,但它可能是这样的

void AddNode(TreeNodeCollection nodes, Item current, IList<Item> items)
    {
        TreeNode treenode = nodes.Add(current.Value.ToString(), current.Value.ToString());

        var children = items.Where(x => x.Key == current.Value && x.ID != current.ID);
        foreach (var child in children)
        {
            if(items.Where(x => x.Key == child.Value).Count() > 1)
                AddNode(treenode.Nodes, child, items);
        }
    }

答案 1 :(得分:1)

显然,这可以在不绕过第二级节点的子节点两次的情况下完成,以便检查它们中是否有自己的子节点。所以,根据Aaron的建议,我修改了这样的代码:

var roots = items.Where(x => x.Key == x.Value);
foreach (var root in roots)
{
    Add2ndLevelNode(treeView1.Nodes, root, items);
}

功能&#34; Add2ndLevelNode&#34;看起来像这样:

    void Add2ndLevelNode(TreeNodeCollection nodes, Item current, IList<Item> items)
    {
        var children = items.Where(x => x.Key == current.Value && x.ID != current.ID);
        bool doIt = false;
        foreach (var child in children)
        {
            if (items.Any(x => x.Key == child.Value))
                doIt = true;
        }
        if (doIt)
        {
            TreeNode treenode = nodes.Add(current.Value.ToString(), current.Value.ToString());

            foreach (var child in children)
            {
                AddNode(treenode.Nodes, child, items);
            }
        }
    }