如果在树视图中选中任何单个子节点,请选择父节点

时间:2013-08-14 14:48:16

标签: c# winforms

我有一个树视图,它有一些父节点和子节点。如果选择子节点,则应选择父节点。此功能正常工作,但如果父节点有多个子节点,并且我检查了多个子节点并取消选中,则取消选中一个子节点父节点。

如果选择了子节点,我已经完成了选择父节点的一些代码。

private bool updatingTreeView;

private void treSelector_AfterCheck(object sender, TreeViewEventArgs e)
{
    if (updatingTreeView) return;
    updatingTreeView = true;
    SelectParents(e.Node, e.Node.Checked);
    updatingTreeView = false;
}

private void SelectParents(TreeNode node, Boolean isChecked)
{
    if (node.Parent != null)
    {
        node.Parent.Checked = isChecked;
        SelectParents(node.Parent, isChecked);
    }
}

如果检查了该父节点的任何单个子节点,我不希望未经检查的父节点。

5 个答案:

答案 0 :(得分:7)

private void SelectParents(TreeNode node, Boolean isChecked)
{
    var parent = node.Parent;

    if (parent == null)
        return;

    if (isChecked)
    {
        parent.Checked = true; // we should always check parent
        SelectParents(parent, true);
    }
    else
    {
        if (parent.Nodes.Cast<TreeNode>().Any(n => n.Checked))
            return; // do not uncheck parent if there other checked nodes

        SelectParents(parent, false); // otherwise uncheck parent
    }
}

相同,重构

private void SelectParents(TreeNode node, Boolean isChecked)
{
    var parent = node.Parent;

    if (parent == null)
        return;

    if (!isChecked && HasCheckedNode(parent))
        return;

    parent.Checked = isChecked;
    SelectParents(parent, isChecked);
}

private bool HasCheckedNode(TreeNode node)
{
    return node.Nodes.Cast<TreeNode>().Any(n => n.Checked);
}

答案 1 :(得分:1)

如果您取消选中某个项目,将会引发事后检查事件,您将调用SelectParents来传播取消选中。

如果只在选中时才需要行为,只需在e.Node.Checked为true(或选中)时运行SelectParents。 但是,如果您取消选中之前检查过的唯一子项目,则不会取消选中父项(因此您可能检查了父项而未检查任何子项)。

答案 2 :(得分:1)

这是一个完整的例程,如果您检查父级,则选择子级 如果你设置了任何孩子,请检查父母

void tw_AfterCheck(对象发送者,TreeViewEventArgs e){

            if (treeView.Enabled) {
                treeView.AfterCheck -= tw_AfterCheck;

                TreeNode node = e.Node;
                if (node.Nodes != null) 
                    node.Nodes.Cast<TreeNode>().ToList().ForEach(v => v.Checked = node.Checked);

                node = e.Node.Parent;
                while (node != null) {
                    bool set = e.Node.Checked
                               ? node.Nodes.Cast<TreeNode>()
                                .Any(v => v.Checked == e.Node.Checked)
                               : node.Nodes.Cast<TreeNode>()
                                .All(v => v.Checked == e.Node.Checked);
                    if (set) {
                        node.Checked = e.Node.Checked;
                        node = node.Parent;
                    }
                    else
                        node = null;
                }
               treeView.AfterCheck += tw_AfterCheck;
            }
        }

答案 3 :(得分:0)

当您去验证每个父母时,您需要验证该父母的所有孩子,因为您不知道取消选中该节点是否是最后一个:

private void VerifyChecked(TreeNode node)
{
    var current = node;
    while (current != null)
    {
        current.Checked = current.Nodes.Cast<TreeNode>()
            .Any(child => child.Checked);
        current = current.Parent;
    }
}

请注意,我重构了它以验证传入的节点,而不是其父节点,因此您需要修改调用它以传递e.Node.Parent

答案 4 :(得分:0)

在创建类似功能时,我引用了此文章和其他文章,并认为我会分享,以防它对其他人有帮助。

所需功能:

检查父节点将检查所有子节点。

取消选中子节点将取消选中所有父节点,以表示未选中所有子节点。

    /// <summary>
    /// Propagates checked state downwards to all children and upwards unchecked to parents.
    /// Parents are unchecked to visually signify that not all children are checked.
    /// </summary>
    /// <param name="currentNode"></param>
    /// <param name="nodeChecked"></param>
    private void CheckedUncheckedPropagateTreeNode(TreeNode currentNode, bool nodeChecked)
    {
        // Check if current node has children.
        foreach (TreeNode node in currentNode.Nodes)
        {
            // Update checked status of this child node.
            node.Checked = nodeChecked;

            // Recursively call method to handle all children of this child node.
            CheckedUncheckedPropagateTreeNode(node, nodeChecked);
        }

        // If the node was unchecked uncheck all parent nodes.
        if (!nodeChecked)
        {
            // Set parent node initial if available.
            TreeNode parentNode = currentNode.Parent;

            // Traverse tree nodes upwards to uncheck all parents.
            while (parentNode != null)
            {
                // Set parent checked value.
                parentNode.Checked = nodeChecked;

                // Set new parent node to continue while loop to the top of the tree view.
                parentNode = parentNode.Parent;
            }
        }
    }