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 ;)
Related
Keep in mind, i am not very experienced with c#.
I am coding a remove button for a list box and the basic function of removing the selected item works.
listBoxSum.Items.RemoveAt(listBoxSum.SelectedIndex);
I'm trying to make an IF statement which will allow me to select an item from my list-box and have it identify the text inside of it (Most likely a string).
As i don't know too much about c#, this is what i currently have for the if statement (obviously the first line is error).
if (listBoxSum.SelectedItem = "Tea")
{
totalCost = totalCost - teaCost;
txtBox_Amount.Text = totalCost.ToString();
}
I have tried making other strings to help simplify the statement like (Below is not the main piece of code for the if statement, the above code is. This was just an experiment on try and extend the code to make it a bit more understandable for myself):
string teaSelect = "Tea" + teaCost;
string selection = (string) listBoxSum.SelectedItem;
if (selection == teaSelect)
{
totalCost = totalCost - teaCost;
txtBox_Amount.Text = totalCost.ToString();
}
Please help, i don't know whether i should change how i'm thinking about this or if it an easy fix hiding in plain sight. Personally i have been stumped on this little button for around 2 hours figuring out how i am going to make the remove button work with the calculations.
If you are not updating your item that holds the "Tea + cost" value, you should probably identify it either by string.StartsWith or maybe assigning it with an identifier of your choice. This could be an integer, an enum or another concrete class with predefined instances.
You can do this by using the Tag property for WPF and creating a simple class for Windows Forms (WPF Tag Property).
A simple example for Windows Forms would be:
enum FoodType
{
Tea = 2
}
class FoodItem
{
public string Text { get; set; }
public FoodType FoodType { get; set; }
public override string ToString()
{
return Text;
}
}
When you are adding your items:
listBoxSum.Items.Add(new FoodItem
{
FoodType = FoodType.Tea,
Text = "Tea " + teaCost
});
And when you are filtering them:
if (listBoxSum.SelectedItem is FoodItem foodItem && foodItem.FoodType == FoodType.Tea)
{
// Do work
}
It is even easier for WPF:
enum FoodType
{
Tea = 1
}
Adding items:
listBoxSum.Items.Add(new ListBoxItem
{
Content = "Tea " + teaCost,
Tag = FoodType.Tea
});
Identifying items:
if (listBoxSum.SelectedItem is ListBoxItem foodItem && foodItem.Tag is FoodType foodType && foodType == FoodType.Tea)
{
MessageBox.Show("hi");
}
What you want to check is whether the item you are currently looking at is a ListBoxItem, and if so, is the contained content a text and is this text equal to your desired text, in order to identify the correct item.
var content = (((x.SelectedItem as ListBoxItem)?.Content as string);
if (content != null && content == "MyDesiredText") {...}
This would be a valid, but not an elegant solution.
A better way would be to remember the listbox items while creating them
var desiredListBoxItem = new ListBoxItem(...)
x.AddChild(desiredListBoxItem);
and afterwards, check whether the object references match:
if (x.SelectedItem == desiredListBoxItem) {...}
So your item in ListBox is called "Tea"?If it is your if statement should look something like this:
if(yourTextBox.Items[yourTextBox.SelectedIndex] == "Tea")
{
//Your Code
}
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--)
{
...
}
I am trying yo create a method that will take a value of one list box and will also be taken out of another list box at the same index. I am just a beginner to C# which is why I am having this problem. Thanks in advance for any help
if (lstCheckoutProduct.)
{
lstCheckoutProduct.Items.Remove(lstCheckoutProduct.SelectedItem);
int productIndex = lstCheckoutProduct.Items.IndexOf(lstCheckoutProduct.SelectedIndex);
lstCheckoutPrice.Items.Remove(productIndex);
}
else
{
lstCheckoutPrice.Items.Remove(lstCheckoutPrice.SelectedItem);
int priceIndex = lstCheckoutPrice.Items.IndexOf(lstCheckoutPrice.SelectedIndex);
lstCheckoutPrice.Items.Remove(priceIndex);
}
You need to get the SelectedIndex before removing the items. Also I assume your first line should check if the listbox is focused
And if you want to remove an item at a specific index you need to use RemoveAt instead of Remove.
if (lstCheckoutProduct.IsFocused)
{
int productIndex = lstCheckoutProduct.SelectedIndex;
lstCheckoutProduct.Items.Remove(lstCheckoutProduct.SelectedItem);
lstCheckoutPrice.Items.RemoveAt(productIndex);
}
else
{
int priceIndex = lstCheckoutPrice.SelectedIndex;
lstCheckoutPrice.Items.Remove(lstCheckoutPrice.SelectedItem);
lstCheckoutProduct.Items.RemoveAt(priceIndex);
}
EDIT: The first line is just a guess as you left it out in your question. Note that IsFocused will be false if the user has clicked a "Remove"-button (and thereby focussed the button instead of the listbox) to call this method.
EDIT: and you can reduce the code to this:
int index = lstCheckoutProduct.IsFocused ? lstCheckoutProduct.SelectedIndex : lstCheckoutPrice.SelectedIndex;
lstCheckoutProduct.Items.RemoveAt(index);
lstCheckoutPrice.Items.RemoveAt(index);
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);
Let's say I have 7 group boxes but some of them also have group box inside them and some do not.
now if I want to iterate through those 7 group boxes and apply something to them, is there a way that I can exclude those Child group boxes from this loop?
though i question the choice of implementation (can you use polymorphism instead? what exactly are you trying to do?), there is a Parent property, e.g.
void soSomething(Control ctrl)
{
if (ctrl is GroupBox && (ctrl.Parent is null || !(ctrl.Parent is GroupBox)))
{
//do something here
}
foreach(Control child in ctrl.Controls)
{
doSomething(child);
}
}
Mark them with the tag property, or something.