3

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

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

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

如果选中了该父节点的任何单个子节点,我不想要未选中的父节点。

4

5 回答 5

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);
}
于 2013-08-14T15:05:08.683 回答
2

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

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;
            }
        }
于 2014-02-18T14:02:01.650 回答
1

如果取消选中某个项目,则会引发 aftercheck 事件,并且您将调用 SelectParents 来传播取消选中。

如果您只希望在选中时的行为,只需在 e.Node.Checked 为真(或选中)时运行 SelectParents。但是,如果您取消选中之前检查过的唯一子项,这不会取消选中父项(因此您可能在没有检查任何子项的情况下检查了父项)。

于 2013-08-14T14:56:50.760 回答
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

于 2013-08-14T15:02:25.037 回答
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;
            }
        }
    }
于 2020-11-21T23:31:13.390 回答