【问题标题】:Populating a TreeView from a list, without root nodes whose children will not have children从列表中填充 TreeView,没有其子节点没有子节点的根节点
【发布时间】:2014-04-03 11:30:35
【问题描述】:

使用 .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,这样根 Tree 节点就是那些具有相同 Key 和 Value 的节点。我就是这样做的:

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

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

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

为了更清楚,这是我在填充 TreeView 后用来清理 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);
}

“Add2ndLevelNode”函数如下所示:

    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 循环。

【问题讨论】:

    标签: c# winforms list treeview children


    【解决方案1】:

    如果孩子的计数超过 1,在进入第二级之前检查,这个 sn-p 是原始的,但它可能是这样的

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

    【讨论】:

    • 请注意,我只想省略根节点。将此代码添加到此函数会将规则应用于所有级别。不是吗?
    • 是的,正确...您可以通过设置全局变量来跟踪当前级别,该全局变量将随着每个递归循环递增,并在回溯发生时重置,或者如果您只想为第二级制定规则,然后如果应用规则,将调用递归方法的单独方法...
    • 这似乎不对。如果我添加一个函数来添加二级节点并在调用递归函数之前检查二级节点是否有子节点,该函数将省略没有子节点的二级节点,而不是根。
    • 查看我的编辑,我已根据您的回答添加了一个可能的解决方案。
    【解决方案2】:

    显然,如果不循环 2 级节点的子节点两次以检查它们是否有自己的子节点,就无法做到这一点。因此,根据 Aaron 的建议,我将代码修改如下:

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

    函数“Add2ndLevelNode”如下所示:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-06-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多