Re: Problem with collections
You cannot modify a collection while iterating through it. For example, consider this code:
Code:
foreach ( string s in someCollection )
{
someCollection.Remove( s );
}
So, how does the iterator continue? You have changed the collection that the iterator was based on, it's state has been changed. If you change that code to this you will not get an exception, but it will also not do what you think it will:
Code:
for ( int i = 0; i < str.Count; ++i )
{
str.Remove( str[i] );
}
That will not remove every element from str, it will remove three elements and miss two of them because "Count" changes as you remove items. So, what I usually do is add each item you want to remove to a separate collection and then iterate through that and remove the items from the first, or, simply iterate backwards through the collection using a for loop.
Code:
for ( int i = str.Count - 1; i >= 0; --i )
{
str.Remove( str[i] );
}
Re: Problem with collections
The error message is pretty descriptive and does tell you where the problem is. Imagine you are driving a car and someone just removes one of the wheels from it, how would the car respond? IN a similar manner, you are trying to remove an item from collection while you are enumerating through it. The ideal solution would be not to remove the items in the same loop. You just select the items (save them in an array our another temporary collection) that need to be removed and then use another foreach loop to remove them from the collection.
Re: Problem with collections
You cannot edit the list you're iterating through inside of a foreach loop. So this line here is whats causing the error. It's dangerous to do this.
Code:
gbl_lisjt.lijst.RemoveAll(d => d.Tname == lbnames.SelectedValue.ToString());
Its possible to work around this but I never suggesting removing items from a list when you're inside the loop iterating through that list.
One thing you can do is create a copy of that list and iterate through the copy and only remove them from the master list. This will stop the error but I don't recommend it.
Code:
foreach(Territories oTerritory in gbl_lisjt.lijst.ToList())
However, its never a good idea to remove items in a list when you are iterating through that list. There must be some other way to redesign your code so this doesn't happen. Rewrite the edit function like this, and you shouldn't get any errors.
Code:
private void btnEditSelected_Click(object sender, RoutedEventArgs e)
{
String getSelected = lbnames.SelectedItem.ToString();
List<Territories> matches = gbl_lisjt.lijst.FindAll(name => name == getSelected);
foreach (Territories oTerritory in matches)
{
tbName.Text = getSelected;
tbsmallx.Text = oTerritory.Sx.ToString();
tbsmally.Text = oTerritory.Sy.ToString();
tblargex.Text = oTerritory.Lx.ToString();
tblargey.Text = oTerritory.Ly.ToString();
if (oTerritory.CbS)
cbStarting.IsChecked = true;
if (oTerritory.CbN)
cbNeutral.IsChecked = true;
if (oTerritory.CbK)
cbKiller.IsChecked = true;
if (oTerritory.CbB)
cbBombard.IsChecked = true;
gbl_lisjt.lijst.RemoveAll(d => d.Tname == lbnames.SelectedValue.ToString());
}
}
Notice how I selected only the objects that I needed to work with and then iterated through those. This allows me to remove anything I want from the original list because i'm not longer iterating through that list.
Re: Problem with collections
Thanks guys!
I have modified my code and I now have this:
Code:
private void btnEditSelected_Click(object sender, RoutedEventArgs e)
{
getSelected = lbnames.SelectedItem.ToString();
for (int i = gbl_lisjt.lijst.Count - 1; i >= 0; i--)
{
Territories oTerritory = gbl_lisjt.lijst[i];
correctName = oTerritory.Tname.ToString();
if (correctName.Equals(getSelected) == true)
{
tbName.Text = getSelected;
tbsmallx.Text = oTerritory.Sx.ToString();
tbsmally.Text = oTerritory.Sy.ToString();
tblargex.Text = oTerritory.Lx.ToString();
tblargey.Text = oTerritory.Ly.ToString();
if (oTerritory.CbS == true)
{
cbStarting.IsChecked = true;
}
else
cbStarting.IsChecked = false;
if (oTerritory.CbN == true)
{
cbNeutral.IsChecked = true;
}
else
cbNeutral.IsChecked = false;
if (oTerritory.CbK == true)
{
cbKiller.IsChecked = true;
}
else
cbKiller.IsChecked = false;
if (oTerritory.CbB == true)
{
cbBombard.IsChecked = true;
}
else
cbBombard.IsChecked = false;
}
if (oTerritory.Tname == getSelected)
{
gbl_lisjt.lijst.RemoveAt(i);
lbnames.Items.RemoveAt(lbnames.SelectedIndex);
System.Diagnostics.Debug.WriteLine("Territories collection(lijst) now contains " + dbgCount.ToString() + " items");
}
}
}
This seems to work fine!
Premier2k
Re: Problem with collections
A side note.
Code:
if (cbBombard.IsChecked == true)
{
if (cbStarting.IsChecked == true)
{
gbl_lisjt.lijst.Add(new Territories(tname, sx, sy, lx, ly, true, false, false, true));
}
else if (cbNeutral.IsChecked == true)
{
if (cbKiller.IsChecked == true)
{
gbl_lisjt.lijst.Add(new Territories(tname, sx, sy, lx, ly, false, true, true, true));
}
else
{
gbl_lisjt.lijst.Add(new Territories(tname, sx, sy, lx, ly, false, false, true, true));
}
}
else if (cbKiller.IsChecked == true)
{
if (cbNeutral.IsChecked == true)
{
gbl_lisjt.lijst.Add(new Territories(tname, sx, sy, lx, ly, false, true, true, true));
}
else
{
gbl_lisjt.lijst.Add(new Territories(tname, sx, sy, lx, ly, false, false, true, true));
}
}
else
{
gbl_lisjt.lijst.Add(new Territories(tname, sx, sy, lx, ly, false, false, false, true));
}
}
else
{
if (cbStarting.IsChecked == true)
{
gbl_lisjt.lijst.Add(new Territories(tname, sx, sy, lx, ly, true, false, false, false));
}
else if (cbNeutral.IsChecked == true)
{
if (cbKiller.IsChecked == true)
{
gbl_lisjt.lijst.Add(new Territories(tname, sx, sy, lx, ly, false, true, true, false));
}
else
{
gbl_lisjt.lijst.Add(new Territories(tname, sx, sy, lx, ly, false, false, true, false));
}
}
else if (cbKiller.IsChecked == true)
{
if (cbNeutral.IsChecked == true)
{
gbl_lisjt.lijst.Add(new Territories(tname, sx, sy, lx, ly, false, true, true, false));
}
else
{
gbl_lisjt.lijst.Add(new Territories(tname, sx, sy, lx, ly, false, false, true, false));
}
}
else
{
gbl_lisjt.lijst.Add(new Territories(tname, sx, sy, lx, ly, false, false, false, false));
}
}
Can be re-written in one line. At least i think it can if I understand what you're trying to do. Just a thought.
Code:
gbl_lisjt.lijst.Add(new Territories(tname, sx, sy, lx, ly, cbStarting.IsChecked, cbKiller.IsChecked, cbNeutral.IsChecked, cbBombard.IsChecked));
Before you copy and past code, take a second to see if you can find some way to do it without copying and pasting. Anytime i catch myself doing this i change my code, it makes it soooo much easier to read. Instead of it takeing me 4 minutes to understand what you're trying to type it takes 2 seconds. Try it, you'll see what i mean.