如何高效地从TreeView中删除选中的项目?

7
如何轻松遍历TreeView中的所有节点,检查它们的.Checked属性,然后删除所有已选中的节点?
这似乎很简单,但你不能通过正在迭代的集合来修改它,因此无法使用“foreach”循环。(调用.Nodes.Remove正在修改集合。)如果尝试这样做,其效果是仅删除了大约一半的.Checked节点。
即使使用两个步骤:首先创建一个临时索引列表,然后在第二个步骤中按索引删除 - 索引也会随着每次删除而更改,从而使索引列表的完整性失效。
那么,最有效的方法是什么呢?
下面是一个看起来很好的代码示例,但实际上只删除了约一半的.Checked节点:
            foreach (TreeNode parent in treeView.Nodes)
            {
                if (parent.Checked)
                {
                    treeView.Nodes.Remove(parent);
                }
                else
                {
                    foreach (TreeNode child in parent.Nodes)
                    {
                        if (child.Checked) parent.Nodes.Remove(child);
                    }
                }
            }

(是的,意图只是从树中修剪两级深度的节点。)
4个回答

8

尝试反向遍历节点。这样,您的索引就不会超过节点大小:

for(int ndx = nodes.Count; ndx > 0; ndx--)
{
  TreeNode node = nodes [ndx-1];
  if(node.Checked)
  {
     nodes.Remove(node);
  }
   // 递归遍历子节点...
}

这是最有效的方法。 - Romias
老问题,但+1是最有效的方法。 - TimFoolery
重新审视一下...进行一些修改可以使它稍微快一些...在for循环标题中进行以下更改:int ndx = nodes.Count-1并且ndx >= 0将使你避免每次通过循环时发生的-1。总体来说,多几次减法并不意味着太多,但是嘿...为什么不呢? - TimFoolery

7

这将在枚举完节点后删除它们,并可以递归地用于n层节点。

void RemoveCheckedNodes(TreeNodeCollection nodes)
{
    List<TreeNode> checkedNodes = new List<TreeNode>();

    foreach (TreeNode node in nodes)
    {
        if (node.Checked)
        {
            checkedNodes.Add(node);
        }
        else
        {
            RemoveCheckedNodes(nodes.ChildNodes);
        }
    }

    foreach (TreeNode checkedNode in checkedNodes)
    {
        nodes.Remove(checkedNode);
    }
}

3
如果想要高效地执行此操作,您需要在节点被选中时跟踪它们的状态。将选中的树节点存储在列表中(并在取消选中时将其移除)。
如果您有一个唯一的键和大量需要跟踪的节点,则可以考虑使用字典。但是,如果您只处理10-50个节点,则可能不会有太大的区别。
然后,不必遍历整个树,只需遍历您(较小的)节点列表即可。

1
在迭代过程中,您可以构建一个未选中项目的新列表,然后将您的树形视图重新绑定到该新列表(丢弃旧列表)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接