TreeViewからチェックされたアイテムを効率的に削除する方法
質問
TreeViewのすべてのノードを簡単に反復処理し、それらの.Checkedプロパティを調べてから、チェックされたすべてのノードを削除するにはどうすればよいですか?
一見簡単そうに思えますが、繰り返しの対象となるコレクションを変更することは想定されておらず、「foreach」の可能性を排除します。ループ。 (.Nodes.Remove呼び出しはコレクションを変更します。)これを試行すると、.Checkedノードの約半分のみが削除されます。
2つのパスを使用する場合でも、最初に一時インデックスのリストを作成し、次に2番目のパスでインデックスごとに削除します。インデックスは削除するたびに変更され、インデックスリストの整合性が無効になります。
では、これを行う最も効率的な方法は何ですか?
これは見栄えの良いコードの例ですが、実際に削除されるのは.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);
}
}
}
(はい、意図は深さ2レベルのツリーからノードをプルーニングすることです。)
解決
これは、ノードを列挙した後に削除し、ノードの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);
}
}
他のヒント
ノードを逆方向に歩いてみてください。そうすれば、インデックスがノードサイズを超えて増加することはありません。
for( int ndx = nodes.Count; ndx > 0; ndx--) { TreeNode node = nodes[ndx-1]; if (node.Checked) { nodes.Remove(node); } // Recurse through the child nodes... }
効率的に実行する場合は、チェックされているノードをチェックしながら追跡する必要があります。チェックされたツリーノードをリストに保存します(チェックされていないため削除します)。
一意のキーと追跡するノードがたくさんある場合は、辞書も検討してください。ただし、10〜50だけを扱っている場合、おそらく大きな違いはありません。
その後、ツリー全体をループする代わりに、ノードの(より小さい)リストをループします。
繰り返しながら、未チェックのアイテムの新しいリストを作成し、ツリービューをその新しいリストに再バインドできます(古いリストを破棄します)。