How do I loop through items in a list box and then remove those item?
Asked Answered
B

8

23

I'm getting the error below when trying to loop through a listbox and then remove the item.

List that this enumerator is bound to has been modified. An enumerator can only be used if the list does not change.

foreach (string s in listBox1.Items)
{
    MessageBox.Show(s);
    //do stuff with (s);
    listBox1.Items.Remove(s);
}

How can I remove the item and still loop through the contents?

Bowler answered 19/12, 2008 at 9:12 Comment(0)
I
40

Do you want to remove all items? If so, do the foreach first, then just use Items.Clear() to remove all of them afterwards.

Otherwise, perhaps loop backwards by indexer:

listBox1.BeginUpdate();
try {
  for(int i = listBox1.Items.Count - 1; i >= 0 ; i--) {
    // do with listBox1.Items[i]

    listBox1.Items.RemoveAt(i);
  }
} finally {
  listBox1.EndUpdate();
}
Implosion answered 19/12, 2008 at 9:15 Comment(4)
Me too Marc. +1 to counter act the injustice of it.Hardshell
I'd love to know the reason for downvotes. Both for me and you! +1Misesteem
@Binary Worrier: In fact upvotes do not really neutralize downvotes, due to 200 points reputation limit.Misesteem
@MehrdadAfshari But they do neutralize the negative effect they have on the answer's score. +1! :)Frowsty
B
26

Everyone else has posted "going backwards" answer, so I'll give the alternative: create a list of items you want to remove, then remove them at the end:

List<string> removals = new List<string>();
foreach (string s in listBox1.Items)
{
    MessageBox.Show(s);
    //do stuff with (s);
    removals.Add(s);
}

foreach (string s in removals)
{
    listBox1.Items.Remove(s);
}

Sometimes the "work backwards" method is better, sometimes the above is better - particularly if you're dealing with a type which has a RemoveAll(collection) method. Worth knowing both though.

Bermuda answered 19/12, 2008 at 9:31 Comment(5)
-1. listBox1.Items might contain objects other than string, in that case InvalidCastException will be thrown.Misesteem
If that were the case, the foreach loop in the sample code in the question would already have blown up. I was making the same assumption as the question did, which I think is pretty reasonable.Bermuda
Yeah, I noticed it. It was just fun to downvote you for a reason for a minutes ;)Misesteem
At least you gave a reason :)Bermuda
One day my rep will be greater than Jons and Mehdrad's combined. Muhahahaha! Assuming that people are required to give a reason for down-voting, of course.Nomography
M
12

Here my solution without going backward and without a temporary list

while (listBox1.Items.Count > 0)
{
  string s = listBox1.Items[0] as string;
  // do something with s
  listBox1.Items.RemoveAt(0);
}
Monopetalous answered 19/12, 2008 at 10:12 Comment(1)
@Fernando68 as the count of the ListBox is decreased every time an item is removed, the while condition will eventually equate to false and the loop will end.Idiomatic
M
2

You have to go through the collection from the last item to the first. this code is in vb

for i as integer= list.items.count-1 to 0 step -1
....
list.items.removeat(i)
next
Marking answered 19/12, 2008 at 9:18 Comment(0)
Q
2

Jefferson is right, you have to do it backwards.

Here's the c# equivalent:

for (var i == list.Items.Count - 1; i >= 0; i--)
{
    list.Items.RemoveAt(i);
}
Quean answered 19/12, 2008 at 9:20 Comment(1)
@Fernando68 Because back in 2008, there were people who can't translate from VB to C# :DQuean
D
2

How about:

foreach(var s in listBox1.Items.ToArray())
{
    MessageBox.Show(s);
    //do stuff with (s);
    listBox1.Items.Remove(s);
}

The ToArray makes a copy of the list, so you don't need to worry about it changing the list while you are processing it.

Desquamate answered 19/12, 2008 at 10:12 Comment(0)
C
2

while(listbox.Items.Remove(s)) ; should work, as well. However, I think the backwards solution is the fastest.

Cenesthesia answered 7/10, 2013 at 9:9 Comment(0)
U
0

You can't make modification to the collection being iterated within the ForEach block.

A quick fix is to iterate over a copy of the collection. An easy way to make this copy is through the ArrayList constructor. The DataRowView objects in the copied collection will refer to, and be able to modify, the same underlying data as your code.

For Each item As DataRowView In New System.Collections.ArrayList(lbOrdersNeedToBeVoided.Items)

please read http://social.msdn.microsoft.com/Forums/en-AU/vbgeneral/thread/b4d1f649-d78a-4e5b-8ad8-1940e3379bed

Us answered 11/1, 2013 at 9:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.