C# 中带有复选框的 TreeView

发布于 2024-10-29 00:42:31 字数 1225 浏览 1 评论 0原文

我在 c# 中有一个带有复选框的树视图,我希望当用户检查一个节点时,自动检查以下级别上的所有节点。 有谁知道如何做到这一点,而无需在每次用户检查某个节点时在所有树上运行递归功能?

谢谢

//这个函数返回treeView。

   public TreeView GetTreeView()
    {

        getSubject();
        // fill the treeview with all subjects.
        foreach (Subject subject in subjects)
        {
            //for each root subject fill all the his children.
            if (subject.subjestId == subject.parentSubject)
            {
                TreeNode node = new TreeNode(subject.subjectString, subject.subjestId, subject.subjestId);
                addChild(node, subject.subjestId);
                tv.Nodes.Add(node);
            }
        }
        return tv;
    }
   // for each subject return sub subjects.
   private void addChild(TreeNode node, int parentId)
    {
        foreach (Subject subject in subjects)
        {
            if (subject.parentSubject == parentId && subject.parentSubject != subject.subjestId)
            {
                TreeNode childNode = new TreeNode(subject.subjectString, subject.subjestId, subject.subjestId);
                addChild(childNode, subject.subjestId);
                node.Nodes.Add(childNode);
            }
        }
    }

I have a tree view with checkboxes in c#, I want that when the user checks one node all the nodes that there are on the levels below automatic checked also.
Does anyone know about way to do that without run with recorsive fnction on all the tree each time that the user checks some node?

Thanks

//this function returns the treeView.

   public TreeView GetTreeView()
    {

        getSubject();
        // fill the treeview with all subjects.
        foreach (Subject subject in subjects)
        {
            //for each root subject fill all the his children.
            if (subject.subjestId == subject.parentSubject)
            {
                TreeNode node = new TreeNode(subject.subjectString, subject.subjestId, subject.subjestId);
                addChild(node, subject.subjestId);
                tv.Nodes.Add(node);
            }
        }
        return tv;
    }
   // for each subject return sub subjects.
   private void addChild(TreeNode node, int parentId)
    {
        foreach (Subject subject in subjects)
        {
            if (subject.parentSubject == parentId && subject.parentSubject != subject.subjestId)
            {
                TreeNode childNode = new TreeNode(subject.subjectString, subject.subjestId, subject.subjestId);
                addChild(childNode, subject.subjestId);
                node.Nodes.Add(childNode);
            }
        }
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

讽刺将军 2024-11-05 00:42:31

递归。像这样:

    bool busy = false;

    private void treeView1_AfterCheck(object sender, TreeViewEventArgs e) {
        if (busy) return;
        busy = true;
        try {
            checkNodes(e.Node, e.Node.Checked);
        }
        finally {
            busy = false;
        }
    }

    private void checkNodes(TreeNode node, bool check) {
        foreach (TreeNode child in node.Nodes) {
            child.Checked = check;
            checkNodes(child, check);
        }

Recursion. Like this:

    bool busy = false;

    private void treeView1_AfterCheck(object sender, TreeViewEventArgs e) {
        if (busy) return;
        busy = true;
        try {
            checkNodes(e.Node, e.Node.Checked);
        }
        finally {
            busy = false;
        }
    }

    private void checkNodes(TreeNode node, bool check) {
        foreach (TreeNode child in node.Nodes) {
            child.Checked = check;
            checkNodes(child, check);
        }
紫瑟鸿黎 2024-11-05 00:42:31
private void treeView1_AfterCheck(object sender, TreeViewEventArgs e) {
  foreach (TreeNode child in e.Node.Nodes) {
    child.Checked = e.Node.Checked;
  }
}
private void treeView1_AfterCheck(object sender, TreeViewEventArgs e) {
  foreach (TreeNode child in e.Node.Nodes) {
    child.Checked = e.Node.Checked;
  }
}
旧人哭 2024-11-05 00:42:31

这是一个更好的解决方案

private void trvMenuList_AfterCheck(object sender, TreeViewEventArgs e)
        {
            SetChildrenChecked(e.Node, e.Node.Checked);

        }

  private void SetChildrenChecked(TreeNode treeNode, bool checkedState)
        {
            foreach (TreeNode item in treeNode.Nodes)
            {
                if (item.Checked != checkedState)
                {
                    item.Checked = checkedState;
                }
                SetChildrenChecked(item, item.Checked);
            }
        }

This is a better solution

private void trvMenuList_AfterCheck(object sender, TreeViewEventArgs e)
        {
            SetChildrenChecked(e.Node, e.Node.Checked);

        }

  private void SetChildrenChecked(TreeNode treeNode, bool checkedState)
        {
            foreach (TreeNode item in treeNode.Nodes)
            {
                if (item.Checked != checkedState)
                {
                    item.Checked = checkedState;
                }
                SetChildrenChecked(item, item.Checked);
            }
        }
只是一片海 2024-11-05 00:42:31

正如许多答案所述,创建一个递归“将检查设置为子项”函数,然后在树上将其称为 AfterCheck。

不幸的是,即使您在代码中设置了检查值,框架也会回调 AfterCheck,尽管这在小树中可能不明显,但会为您的应用程序增加大量指数级的额外工作。为了避免这种情况,请过滤 AfterCheck 以仅在用户触发新函数时才触发该函数。

    private void tree_AfterCheck(object sender, TreeViewEventArgs e)
    {
        if (e.Action != TreeViewAction.Unknown)
        {
            SetChildrenChecked(e.Node);
        }
    }

    private void SetChildrenChecked(TreeNode treeNode)
    {
        foreach (TreeNode item in treeNode.Nodes)
        {
            if (item.Checked != treeNode.Checked)
            {
                item.Checked = treeNode.Checked;
            }

            if (item.Nodes.Count > 0)
            {
                SetChildrenChecked(item);
            }                
        }
    }

As a number of the answers state, create a recursive 'set checked to children' function, then call it AfterCheck on the tree.

The framework unfortunately gives you a call back to AfterCheck even if you set the check value in code, and although this may not be noticeable in small trees adds a massive amount of exponential extra work for your app to do. To avoid it, filter AfterCheck to only fire your new function if it has been triggered by user.

    private void tree_AfterCheck(object sender, TreeViewEventArgs e)
    {
        if (e.Action != TreeViewAction.Unknown)
        {
            SetChildrenChecked(e.Node);
        }
    }

    private void SetChildrenChecked(TreeNode treeNode)
    {
        foreach (TreeNode item in treeNode.Nodes)
        {
            if (item.Checked != treeNode.Checked)
            {
                item.Checked = treeNode.Checked;
            }

            if (item.Nodes.Count > 0)
            {
                SetChildrenChecked(item);
            }                
        }
    }
灯角 2024-11-05 00:42:31

我对答案做了一些扩展;也通过更新父级。 [catch 中的 DisplayException 方法只是我经常使用的弹出窗口;你可以自己做]

    private bool _busy = false;  

    private void treeViewPassFail_AfterCheck(object sender, TreeViewEventArgs e)
    {
        try
        {
            if (_busy)
            {
                return;
            }

            _busy = true;

            CheckNodes(e.Node, e.Node.Checked);

            CheckParent(e.Node.Parent);
        }
        catch(Exception ex)
        {
            DisplayException(ex);
        }
        finally
        {
            _busy = false;
        }
    }

    private void CheckNodes(TreeNode node, bool check)
    {
        foreach(TreeNode child in node.Nodes)
        {
            child.Checked = check;
            CheckNodes(child, check);
        }
    }

    private void CheckParent(TreeNode parent)
    {
        if (parent != null)
        {
            bool allChecked = true;

            foreach (TreeNode node in parent.Nodes)
            {
                allChecked &= node.Checked;
            }

            parent.Checked = allChecked;
        }
    }

I expanded on the answer a little; by updating the parent as well. [The DisplayException method inside the catch is just a popup window that I always use; you can do your own]

    private bool _busy = false;  

    private void treeViewPassFail_AfterCheck(object sender, TreeViewEventArgs e)
    {
        try
        {
            if (_busy)
            {
                return;
            }

            _busy = true;

            CheckNodes(e.Node, e.Node.Checked);

            CheckParent(e.Node.Parent);
        }
        catch(Exception ex)
        {
            DisplayException(ex);
        }
        finally
        {
            _busy = false;
        }
    }

    private void CheckNodes(TreeNode node, bool check)
    {
        foreach(TreeNode child in node.Nodes)
        {
            child.Checked = check;
            CheckNodes(child, check);
        }
    }

    private void CheckParent(TreeNode parent)
    {
        if (parent != null)
        {
            bool allChecked = true;

            foreach (TreeNode node in parent.Nodes)
            {
                allChecked &= node.Checked;
            }

            parent.Checked = allChecked;
        }
    }
南城追梦 2024-11-05 00:42:31

如果你想在 WinForms 中执行此操作,那么我认为你必须通过递归手动执行此操作 - 我不知道有什么更好的方法。

If you want to do it in WinForms then I think you have to do it manually by recursion - I don't know any better way.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文