C# 尝试在treeview中设置所有节点的检查状态-get StackOverflowException

C# 尝试在treeview中设置所有节点的检查状态-get StackOverflowException,c#,winforms,treeview,C#,Winforms,Treeview,我将一些节点添加到我的树视图(trvP)。根元素的Tag属性设置为root 我试图使它成为这样,如果我检查根元素,所有其他节点将具有相同的状态。但是,执行下面的代码会导致StackOverflowException private void trvP_AfterCheck(object sender, TreeViewEventArgs e) { if(e.Node.Tag.Equals("Root")) { var nodes = Tre

我将一些节点添加到我的
树视图(trvP)。根元素的
Tag
属性设置为
root

我试图使它成为这样,如果我检查根元素,所有其他节点将具有相同的状态。但是,执行下面的代码会导致
StackOverflowException

private void trvP_AfterCheck(object sender, TreeViewEventArgs e)
{
        if(e.Node.Tag.Equals("Root"))
        {
            var nodes = TreeViewExtensions.GetAllNodes(e.Node.TreeView);
            foreach (TreeNode node in nodes)
                node.Checked = e.Node.Checked;
        }
}
GetAllNodes
函数的代码:

public static List<TreeNode> GetAllNodes(this TreeView _trv)
{
        List<TreeNode> result = new List<TreeNode>();
        foreach (TreeNode child in _trv.Nodes)
        {
            result.AddRange(child.GetAllNodes());
        }
        return result;
}
public static List<TreeNode> GetAllNodes(this TreeNode _trn)
    {
        List<TreeNode> result = new List<TreeNode>();
        result.Add(_trn);
        foreach (TreeNode child in _trn.Nodes)
        {
            result.AddRange(child.GetAllNodes());
        }
        return result;
    }
公共静态列表GetAllNodes(此树视图)
{
列表结果=新列表();
foreach(节点中的TreeNode子节点)
{
result.AddRange(child.GetAllNodes());
}
返回结果;
}
公共静态列表GetAllNodes(此树节点)
{
列表结果=新列表();
结果。添加(\u trn);
foreach(节点中的TreeNode子节点)
{
result.AddRange(child.GetAllNodes());
}
返回结果;
}
从调试中可以看出,它反复运行
var nodes=…
代码段,而只在
foreach
循环(根节点)中设置单个节点。但是,
节点
是具有正确值的节点的适当列表


我不明白为什么这会一次又一次地执行,导致异常。

您正在递归调用GetAllNodes,这会使循环进入无限状态

试一试

公共静态列表GetAllNodes(此树视图)
{
列表结果=新列表();
foreach(节点中的TreeNode子节点)
{
结果:添加(儿童);
}
返回结果;
}
当您已经将treenode循环到_trv.Nodes中时,您需要将当前节点添加到foreach语句中。

您的
GetAllNodes()
扩展以
TreeView
的第一个子节点开始,并为此
treenode调用
GetAllNodes()
扩展

GetAllNodes()
扩展将此
TreeNode
添加到结果列表中。
因此,列表中的第一个
树节点再次成为根节点

这意味着排队

node.Checked = e.Node.Checked;
您可以设置根节点的
Checked
属性,该属性反过来为该根节点再次调用处理程序
trvP\u AfterCheck
。这将无限重复,淹没堆栈并引发
StackOverflowException

要解决此问题,请过滤掉根节点:

private void trvP_AfterCheck(object sender, TreeViewEventArgs e)
{
        if(e.Node.Tag.Equals("Root"))
        {
            var nodes = e.Node.TreeView.GetAllNodes();
            foreach (TreeNode node in nodes)
            {
                if (node == e.Node) continue; // don't do it for root again
                node.Checked = e.Node.Checked;
            }
        }
}

顺便说一句:扩展方法的好处在于,您可以在语法上调用它们,就好像它们是instanc方法一样。那么这个

var nodes = TreeViewExtensions.GetAllNodes(e.Node.TreeView)
可以简单地写为

var nodes = e.Node.TreeView.GetAllNodes();

你能为
TreeNode
显示
GetAllNodes()
扩展名吗(你只显示
TreeView
的扩展名)?我猜根节点将是列表中的第一个,因此
node.Checked=…
将为同一节点再次调用处理程序
trvP\u AfterCheck()
(虽然如果checkstate没有更改,则不应该发生这种情况)。添加了,但如下面所述,
GetAllNodes
如果为某个随机子元素(也有子元素)调用它,效果很好-只有根元素会导致问题。不,它会遗漏子节点。在OP的代码中,递归调用似乎是正确的,因为当下面没有子节点时,递归停止。GetAllNodes工作正常,当我将它与其他一些
标记一起使用时,它会按预期工作,只有在尝试处理
元素时,它才会抛出错误沃格特说:“例外。”我认为他只需要通过结点的父母而错过。我不认为一个完整的清单会一再地引起这一事件,这是一个很好的解释,谢谢。
var nodes = e.Node.TreeView.GetAllNodes();