This question already has answers here:
RemoveAll for ObservableCollections?
(8 answers)
Closed 5 years ago.
I am looping through an ObservableCollection for items that have been marked by setting a boolean to true. After doing what I need with the item I want to remove it from the OnservableCollection. I can't do that within the foreach loop, so I was thinking of making a list of all the items marked, then after the foreach loop just clear all the items from the collection at once. But I can't even get started because I don't know how to get the index of the item in the foreach loop.
private void Upload()
{
List<TestResult> kill;
foreach (var tr in TestResults)
{
if (tr.CanUpload)
{
StatusContent = "Uploading " + tr.FileName;
FileOps.UploadDocument(tr);
kill.Add(tr);
tr.CanUpload = false;
RaisePropertyChanged("TestResults");
}
}
//this doesn't work
//TestResults.Remove(TestResults.Where(x => x.CanUpload == true));
}
I've tried working with what I have above, but I am missing some critical pieces to make it work right.
Use a for loop instead. Like you noticed you can not remove items in a collection you are looping with a foreach.
But you have to update your current item index when removing items ;)
Something like this should do the work
for (var i = myList.Count() - 1; i >= 0; i--)
{
...
}
Related
This question already has answers here:
How add or remove object while iterating Collection in C#
(6 answers)
Closed 2 months ago.
I have a StackPanel that holds Usercontrols, these UserControls are replaced, animated, etc on user input. At specific times I would like to make sure that only the currently active view is present in the stackpanel. I tried with a function like this
public void cleanupStackPanel(UserControl ctrl)
{
foreach (UserControl item in contentContainer.Children)
{
if(item != ctrl)
{
contentContainer.Children.Remove(item);
}
}
}
But upon calling, it says "enumerator is not valid because the collection changed". How could I change this to achieve the result I want?
You cannot remove items inside of an foreach loop. Use a for loop instead, but be careful: when removing items you have to manipulate the index parameter too!
public void cleanupStackPanel(UserControl ctrl)
{
for ( int i = 0; i < contentContainer.Children.Count; i++ )
{
var item = (UserControl) contentContainer.Children[i];
if(item != ctrl)
{
contentContainer.Children.Remove(item);
i--;
}
}
}
I could not test this code, because your example is missing of the surrounded class. So I guessed that contentContainer.Children has a Count property ... but instead it could also be Length. But I am sure, you will find the correct way of determining the number of children ;)
This question already has answers here:
Collection was modified; enumeration operation may not execute
(16 answers)
Closed 1 year ago.
I have a list with some old values that I want to delete, but it throws a System.InvalidOperatonException saying the collection was changed after creating an object. If I don't use the else statement, it is working all right.
foreach (var item in list) // here is exception
{
if (DateTime.Parse(item.Key.ToShortDateString()) > DateTime.Parse("12.09.2020"))
{
panel.Controls.Add(new Label()
{
Text = item.Key.ToString().Remove(10) + "\n" + item.Key.ToString().Remove(0, 10) + "\n" + item.Value.ToString(),
AutoSize = true
});
month.AddBoldedDate(item.Key);
}
else
{
list.Remove(item.Key); // I want to delete an old element
}
}
How can I fix this problem?
You cannot change a List when enumerating it. You should iterate on the list on items to remove.
foreach(var item in list)
{
//...
else
{
keysToRemove.Add(item.Key);
}
}
foreach(var key in keysToRemove)
{
list.Remove(key);
}
In foreach loops, the compiler in the background is creating an 'enumerator' - a structure that moves through the set of items 1 item at a time, and it feeds those items into the loop body.
If you alter items in the set of items while you are in the loop, this can have unpredictable consequences. To avoid this issue, create a copy of the list that you don't modify and use that as the basis for the loop, then modify the original:
// use list.ToList() to create a second copy of the list
// that will not change when you modify the original
foreach(var item in list.ToList())
{
// ... existing code
}
Instead of removing elements while you're iterating over the list, you should remove them before that iteration like this:
list.RemoveAll(item => DateTime.Parse(item.Key.ToShortDateString()) > DateTime.Parse("12.09.2020"));
At this point all of those items are removed and you can continue with your loop without the else statement:
foreach (var item in list)
{
panel.Controls.Add(new Label()
{
Text = item.Key.ToString().Remove(10) + "\n" + item.Key.ToString().Remove(0, 10) + "\n" + item.Value.ToString(),
AutoSize = true
});
month.AddBoldedDate(item.Key);
}
This question already has answers here:
Is it possible to do start iterating from an element other than the first using foreach?
(5 answers)
Closed 6 years ago.
I have this code:
var rows = sheet.Descendants<Row>().ToList();
foreach (Row row in rows)
{
//some logic
}
In code above I get some rows collection and make List from it,
then I make foreach loop on the List.
I need to make foreach to read from the second item in the list of rows, not from the first item as it implemented.
What the elegant way to implement it?
You can use IEnumerable.Skip
var rows = sheet.Descendants<Row>().ToList(); //.ToList() is not neccesarry for this example, but may be necessary later on.
foreach (Row row in rows.Skip(1))
{
//some logic
}
This will start from the 2nd row.
I have a c# wpf listbox and I am trying to get the values from the selected items. I cannot use a foreach loop (every value I find will remove an item from the listbox). But this seems impossible.
What I want is somthing like this:
for (int i = <numberofselecteditems> - 1; i >= 0; i--)
{
string displaymembervalue = listbox.selecteditem[i].displaymembervalue;
}
I have a solution which involve to loop over all the listbox items twice. This is not really an option since it will slow the app too much.
Like I said before, this is NOT the
System.Windows.Forms.Listbox
but the
System.Windows.Controls.Listbox
thank you!!
J.
See the solution here, it is essentially using a foreach in the follolwing fashion:
foreach (var item in listBox1.SelectedItems)
{
// Do what you want here... Console.WriteLine(item), etc.
}
If you really want to do it with a for loop rather than a foreach, then do the following:
for(int i = selectedItems.Count - 1; i >= 0; --i)
{
var item = selectedItems[i];
// Do what you want with item
}
Here is your XAML bound to a Observable collection
<ListBox ItemsSource="{Binding items}"/>
Here is your observable collection of objects
private ObservableCollection<Object> _items;
public ObservableCollection<Object> items{
get{ return _items; }
}
Here is the enumeration over them and the removing of each item
for(int x = 0; x < _items.Count; x++){
_items.Remove(_items.Where(n => n == _items[x]).Single());
//You may have to do a notify property changed on this if the UI Doesnt update but thats easily googled.
//Traditionally it would update. However since you are bound to items Im not sure if it will update when you manipulate _items
}
Create a second list. You still have to iterate twice, but the second iteration is not over the entire list of items.
var items List<ListBoxItem>;
foreach (var item in listbox1.SelectedItems)
items.Add(item);
foreach (var item in items)
listbox1.Remove(item);
Alternatively instead of enumerating twice you can create a copy of the list of objects and then remove the items from the original list while still enumerating.
foreach (var selectedItem in listBox1.SelectedItems.Cast<List>())
{
//remove items from the original list here
}
This question already has answers here:
What is the best way to modify a list in a 'foreach' loop?
(11 answers)
Closed 9 years ago.
I am currently working on a C# WPF project. I have a list which uses a class to store multiple values. The class is called DBTables and has the following inside:
class DBTables
{
public string selDatabase { get; set; }
public string selTable { get; set; }
}
I am creating a new instance of the list with the following code
List<DBTables> tableArr = new List<DBTables>();
I am adding new items to the List without any problems but the problem I am having is when it comes to removing an item from the list.
A an item is added to the list when a checkbox is selected the item is added and when the checkbox is unchecked the item needs to be removed. Each time the checkbox is checked two values are added using the following code:
private void addBackupArray(string table)
{
backupArr.Add(new DBTables
{
selDatabase = selectedDatabase,
selTable = table
});
}
When the check box is unchecked the values at the position need to be removed and I have sort of got it working but after it has removed the item it then displays the error 'InvalidOperationException, collection was modified; enumeration may not execute'.
Below is the code that I am currently using to remove the item from the list.
private void removeBackupArray(string table)
{
int i = 0;
foreach (DBTables tables in backupArr)
{
if (selectedDatabase == tables.selDatabase && table == tables.selTable)
{
backupArr.RemoveAt(i);
i = 0;
}
i++;
}
}
The code above iterates through the values in the list and based on an if statement of whether the two variables match the value found in the list it removes it at the current position of the counter i.
How can I get round this issue so I can remove the item without getting the error.
Thanks for any help you can provide.
Change the foreach to normal for loop will fix the issue:
for (int tablesIndex = 0; tablesIndex < backupArr.Count; tablesIndex++)
{
var tables = backupArr[tablesIndex];
if (selectedDatabase == tables.selDatabase && table == tables.selTable)
{
backupArr.RemoveAt(tablesIndex);
tablesIndex--;
}
}
Changed your foreach to a for loop. The foreach uses an enumerator to iterate over all of the objects in the List. You can't change the contents of the enumerator within the foreach or you'll get the error you see.
Give this a try instead
int i;
for (i = 0; i < backupArr.Count; i++)
{
DBTables tables = backupArr[i];
if (selectedDatabase == tables.selDatabase && table == tables.selTable)
{
break;
}
}
backupArr.RemoveAt(i);
A neater solution could be to use a linq like so:
DBTables tables = backupArr.Where(t => t.selDatabase == selectedDatabase && t.selTable == table).SingleOrDefault();
if (tables != null)
backupArr.Remove(tables);