你可能不太了解的TreeNode
用了很长时间的TreeView,TreeNode,才发现你不了解他的话,有时候会很不听话的
因为某种需要,我要删除某节点的所有子节点,但是要保持对所有节点的引用,因此不能是用Nodes.Clear()方法来做,所以我遍历该节点的所有子节点,将每个节点从集合中拉出来,扔到一个ArrayList里(当然可以先复制所有节点,然后调用Clear()方法,但我当时没有这么做,否则的话也不会出现下面的问题了)
代码:
ArrayList list = new ArrayList();
TreeNode root = new TreeNode();
root.Nodes.Add(new TreeNode("1"));
root.Nodes.Add(new TreeNode("2"));
root.Nodes.Add(new TreeNode("3"));
root.Nodes.Add(new TreeNode("4"));
foreach( TreeNode curNode in root.Nodes){
Console.WriteLine(curNode.Text);
curNode.Remove();
list.Add(curNode);
}
这段代码好象没什么问题,编译也通过,可是运行出现下面异常:
Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an object.
再看控制台输出,竟然是
1
3
4
4![]()
显然,他跳过了第二个TreeNode,而在最后循环到最后一个TreeNode的时候curNode指向的是已经从父节点Remove掉的节点,好象很奇怪。增加几个节点:
root.Nodes.Add(new TreeNode("1"));
root.Nodes.Add(new TreeNode("2"));
root.Nodes.Add(new TreeNode("3"));
root.Nodes.Add(new TreeNode("4"));
root.Nodes.Add(new TreeNode("5"));
root.Nodes.Add(new TreeNode("6"));
root.Nodes.Add(new TreeNode("7"));
root.Nodes.Add(new TreeNode("8"));
root.Nodes.Add(new TreeNode("9"));
root.Nodes.Add(new TreeNode("10"));
仍然异常,这次再看输出,发现是
1
3
5
7
9
10
10
原来Remove操作影响了循环,每次Remove都减少一个节点,于是curNode总是指向后一个节点而不是下一个节点,所以循环会跳过偶数项了。这个理解了,又有新的问题:当循环遍历最后一个节点10之后,仍然往下走,而不是跳出循环,前面的出现异常显然是在第二次Remove节点10的时候抛出的,为什么会再次引用节点10呢,难道他越界后就不停的循环引用节点10了?
那么我们再改代码,在Remove()之前判断,:
if(curNode.Parent == root){
curNode.Remove();
}
输出是:
1
3
5
7
9
10
10
10
10
10
可以见得Remove 操作虽然改变了循环所引用的对象,但是却没有改变循环的次数,他仍然按照Remove之前的循环次数循环,所以会引发前面的异常。
下面给出我的解决方案:
foreach(TreeNode curNode in root.Nodes){
list.Add(root.Nodes[0]);
root.Nodes[0].Remove();
}
但这样的话curNode声明没有用到,所以改用for,并且逆向循环。
for (int i=root.Nodes.Count; --i >=0;){
Console.WriteLine(root.Nodes[i].Text);
root.Nodes.RemoveAt(i);
}
或者用前面提到的先复制再清除的方法
TreeNodeCollection myTreeNodeCollection = myTreeViewBase.Nodes;
TreeNode[] myTreeNodeArray = new TreeNode[myTreeViewBase.Nodes.Count];
myTreeViewBase.Nodes.CopyTo(myTreeNodeArray,0);
myTreeViewBase.Nodes.Clear();

浙公网安备 33010602011771号