1

I had learnt by reading your great answers here, that it is not good practice deleting items from within a foreach loop, as it is (and I quote) "Sawing off the branch you're sitting on".

My code currently removes the text from the dropdownlist, but the actual item remains (just without text displayed).

In other words, it isn't deleting, and probably can't because you can't delete from within a foreach loop.

After hours of trying I am unable to get my head around a way of doing it.

//For each checked box, run the delete code
for (int i = 0; i < this.organizeFav.CheckedItems.Count; i++)
{
    //this is the foreach loop
    foreach (ToolStripItem mItem in favoritesToolStripMenuItem.DropDownItems)
    {
        //This rules out seperators
        if (mItem is ToolStripMenuItem)
        {
            ToolStripMenuItem menuItem = mItem as ToolStripMenuItem;

            //This matches the dropdownitems text to the CheckedItems String
            if (((ToolStripMenuItem)mItem).Text.ToString() == organizeFav.CheckedItems[i].ToString())
            {
                //And deletes the item
                menuItem.DropDownItems.Remove(mItem);
            }
        }
    }
}

But it isn't deleting because it is within a foreach loop! I would greatly appreciate your help, and be truly amazed if anyone can get their head around this code :)

Kind Regards

5 Answers 5

5

Fun with LINQ!

// Loop through the checked items, same as you did.
foreach (var checkedItem in this.organizeFav.CheckedItems)
{
    // Cast from IEnumerable to IEnumerable<T> so we can abuse LINQ
    var matches = favoritesToolStripMenuItem.DropDownItems.Cast<ToolStripItem>()
                  // Only items that the Text match
                  .Where(item => item.Text == checkedItem.Text)
                  // Don't match separators
                  .Where(item => item is ToolStripMenuItem)
                  // Select the keys for the later .Remove call
                  .Select(item => item.Name);

    // Loop through all matches        
    foreach (var key in matches)
    {
        // Remove them with the Remove(string key) overload.
        favoritesToolStripMenuItem.Remove(key);
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

Yep, Linq would also be my preferred option, but i didn't want to scare the OP with its awesome power :)
3

You don't need a foreach loop - just use a regular loop but go in reverse, start at the end and go to the beginning.

//For each checked box, run the delete code
for (int i = 0; i < this.organizeFav.CheckedItems.Count; i++)
{
    //this *replaces* the foreach loop
    for(int j = favoritesToolStripMenuItem.DropDownItems.Count - 1; j >= 0; j--)
    {
        ToolStripMenuItem menuItem = favoritesToolStripMenuItem.DropDownItems[j] as ToolStripMenuItem; 

        //This rules out seperators
        if (menuItem != null)
        {
            //This matches the dropdownitems text to the CheckedItems String
            if (menuItem.Text.ToString() == organizeFav.CheckedItems[i].ToString())
            {
                favoritesToolStripMenuItem.DropDownItems.Remove(menuItem);
            }
        }
    }
 }

this was @Kurresmack's code rearranged, i just coded it directly here in the page so excuse any small syntax error or anything obvious i overlooked (disclaimer: it is a sample!!)

You can still treat favoritesToolStripMenuItem.DropDownItems as a collection like you were, but you don't have to enumerate over it using a foreach. This cuts down on a few lines of code, and it works because you are iterating it in reverse order, you will not get an index out of bounds exception.

Comments

0

Try something like this:

//For each checked box, run the delete code
for (int i = 0; i < this.organizeFav.CheckedItems.Count; i++)
        {
    List<ToolStripItem> toRemove = new List<ToolStripItem>();
//this is the foreach loop
            foreach (ToolStripItem mItem in favoritesToolStripMenuItem.DropDownItems)
            {

                //This rules out seperators
                if (mItem is ToolStripMenuItem)
                {
                    ToolStripMenuItem menuItem = mItem as ToolStripMenuItem;

             //This matches the dropdownitems text to the CheckedItems String
                    if (((ToolStripMenuItem)mItem).Text.ToString() == organizeFav.CheckedItems[i].ToString())
                    {
                        toRemove.Add(mItem);
                    }
                }
            }
        foreach(var item in toRemove)
        {
        favoritesToolStripMenuItem.DropDownItems.Remove(item);
        }
        }

Comments

0

To my mind, the way to make the code work is:
1. Create an instance of the type the favoritesToolStripMenuItem.DropDownItems collection is.
2. In the foreach loop, add all items, you do not want to be removed, to that collection.
3. Make favoritesToolStripMenuItem.DropDownItems to point to the new collection. Or clear favoritesToolStripMenuItem.DropDownItems and load the items from the new collection to it.

Hope this helps

Comments

0

Instead of a foreach use a reverse for-Loop:

for(int reverseIndex = myList.Count - 1; reverseIndex >= 0; reverseIndex--)
{
    var currentItem = myList[reverseIndex];
    if(MatchMyCondition(currentItem))
    {
        myList.Remove(currentItem);
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.