初学者:在 Winforms 中带有复选框和递归的 TreeView

Beginner: TreeView with checkboxes and recursion in Winforms

首先 post 和一个新的编码器,如果您需要比我提供的更多的信息,请与我联系。我正在尝试在层次结构中创建一个带有复选框的树视图(见图)。我的问题是我想创建某种递归,在检查父节点时取消选择并选择子节点,反之亦然。

我正在将 VS 与 winforms 一起使用,并在谷歌上搜索了 2 天以了解如何执行此操作,不幸的是,在线示例对我来说太高级或不起作用。我发现 Tutorial 关于如何使用不确定的复选框完全做到这一点,这将是一个很大的好处,但它适用于 WPF。

我设法创建了能够(取消)检查所有按钮的按钮,并提供了一些在线示例。请有人指导,一个到目前为止发现编程令人惊叹的初学者,在正确的方向:)

 private void button_checkAllNodes_Click(object sender, EventArgs e)
    {
        checkAllNodes(treeView1.Nodes);
    }

    private void button_uncheckAllNodes_Click(object sender, EventArgs e)
    {
        UncheckAllNodes(treeView1.Nodes);
    }

    public void checkAllNodes(TreeNodeCollection nodes)
     {
         foreach (TreeNode node in nodes)
         {
             node.Checked = true;
             checkChildren(node, true);
         }
     }
    public void UncheckAllNodes(TreeNodeCollection nodes)
    {
        foreach (TreeNode node in nodes)
        {
            node.Checked = false;
            checkChildren(node, false);
        }
    }

    private void checkChildren(TreeNode rootNode, bool isChecked)
     {
         foreach (TreeNode node in rootNode.Nodes)
         {
             checkChildren(node, isChecked);
             node.Checked = isChecked;
         }
     }

    private void treeView1_AfterSelect(object sender, TreeViewEventArgs e)
    {
        
    }

Picture Treeview with (un)check All buttons

我同意@jdweng 的观点,您在 checkChildren() 中使用了递归。缺少基本案例。 在递归 checkChildren 中,在
之前添加基本情况 foreach (TreeNode node in rootNode.Nodes)
if node is Null : rootNode=isChecked

让我们为 TreeNode 类型创建几个扩展方法,一个获取一个节点的所有子节点,另一个获取它的父节点。

// Within your project's namespace...
static class TreeViewExtensions
{
    public static IEnumerable<TreeNode> Children(this TreeNode node)
    {
        foreach (TreeNode n in node.Nodes)
        {
            yield return n;

            foreach (TreeNode child in Children(n))
                yield return child;
        }
    }

    public static IEnumerable<TreeNode> Parents(this TreeNode node)
    {
        var p = node.Parent;

        while (p != null)
        {
            yield return p;

            p = p.Parent;
        }
    }
}

现在,您需要做的就是处理 TreeView.AfterCheck 事件以切换扩展方法产生的节点的 Checked 属性。

// +
using System.Linq;

private void treeView1_AfterCheck(object sender, TreeViewEventArgs e)
{
    if (e.Action == TreeViewAction.Unknown) return;

    foreach (TreeNode n in e.Node.Children())
        n.Checked = e.Node.Checked;

    // Comment this if you don't need it.
    foreach (TreeNode p in e.Node.Parents())
        p.Checked = p.Nodes.OfType<TreeNode>().Any(n => n.Checked);
}

很快,您会注意到有时当您快速单击复选框时此解决方案无法正常工作,因为默认情况下它们不会收到鼠标双击消息。然后,按照 post or 来解决这个问题。现在慢慢点击。

如果您更喜欢使用按钮来切换检查状态,请删除 AfterCheck 处理程序并改为:

private void btnCheckAll_Click(object sender, EventArgs e)
{
    ToggleCheck(treeView1.SelectedNode, true);
}

private void btnUncheckAll_Click(object sender, EventArgs e)
{
    ToggleCheck(treeView1.SelectedNode, false);
}

private void ToggleCheck(TreeNode node, bool state)
{
    node.Checked = state;

    foreach (TreeNode n in node.Children())
        n.Checked = state;

    // Optional...
    foreach (TreeNode n in node.Parents())
        n.Checked = state;
}