【问题标题】:Beginner: TreeView with checkboxes and recursion in Winforms初学者:Winforms 中带有复选框和递归的 TreeView
【发布时间】:2021-04-01 23:19:23
【问题描述】:

如果您需要比我提供的更多信息,第一篇文章和一个新的编码器对我来说如此裸露。我正在尝试使用层次结构中的复选框创建树视图(见图)。我的问题是我想创建某种递归,当父节点被选中时取消选择并选择子节点,反之亦然。

我正在将 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

【问题讨论】:

  • 不确定您的问题是什么。我唯一看到错误的是 rootNode.Nodes 为空。因此,当 rootNode.Nodes 为空时,您需要一个 IF 语句从 CheckAllNodes/UnCheckAllNodes 返回。

标签: c# winforms recursion treeview child-nodes


【解决方案1】:

让我们为 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);
}

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

如果您更喜欢使用按钮来切换检查状态,请删除 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;
}

【讨论】:

  • 嘿,非常感谢你。几乎完全符合我的要求。抱歉,因为我一直在度假,所以回复晚了。我将如何让它即时选中/取消选中?而不是在选定的节点上使用按钮?
  • @Breakwin 欢迎回来。如果您检查我的答案的第一个版本,您会看到该部分。我以为您不需要它,因此我将其删除。我再补充一下。
  • 太棒了,它做到了。非常感谢您。我只需要另外添加 aftercheck 事件。显然,当我创建它时,它没有被添加到树视图中。 docs.microsoft.com/en-us/dotnet/api/…
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 2011-03-23
    • 1970-01-01
    • 1970-01-01
    • 2011-07-12
    • 2018-09-17
    • 2016-09-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多