Foreach every Subitem in a MenuStrip
Asked Answered
T

8

7

I want to get all the SubItems of my MenuStrip, So I can change them all at once.

I'am trying things like the following, but they aren't working:

foreach (ToolStripMenuItem toolItem in menuStrip1.DropDownItems)
{
      //Do something with toolItem here
}

Can someone help me out coding a good foreach loop for getting all the SubMenuItems(DropDownItems) from the MenuStrip?

EDIT now trying to work with the following Recursive method:

private void SetToolStripItems(ToolStripItemCollection dropDownItems)
        {
            try
            {
                foreach (object obj in dropDownItems)
                {
                    if (obj.GetType().Equals(typeof(ToolStripMenuItem)))
                    {
                        ToolStripMenuItem subMenu = (ToolStripMenuItem)obj;

                        if (subMenu.HasDropDownItems)
                        {
                            SetToolStripItems(subMenu.DropDownItems);
                        }
                        else
                        {

                        }
                    }
                }
            }
            catch
            {

            }
        }
Trifurcate answered 13/3, 2013 at 8:56 Comment(3)
Hint: You need to use recursion.Iaea
I'am trying to find a good article for that at the moment...Trifurcate
obj.GetType().Equals(typeof(ToolStripMenuItem)) can be written simply like (obj is ToolStripMenuItem)Iaea
I
8

Try this:

List<ToolStripMenuItem> allItems = new List<ToolStripMenuItem>();
foreach (ToolStripMenuItem toolItem in menuStrip.Items) 
{
    allItems.Add(toolItem);
    //add sub items
    allItems.AddRange(GetItems(toolItem));
}  
private IEnumerable<ToolStripMenuItem> GetItems(ToolStripMenuItem item) 
{
    foreach (ToolStripMenuItem dropDownItem in item.DropDownItems) 
    {
        if (dropDownItem.HasDropDownItems) 
        {
            foreach (ToolStripMenuItem subItem in GetItems(dropDownItem))
                yield return subItem;
        }
        yield return dropDownItem;
    }
}
Iaea answered 13/3, 2013 at 9:58 Comment(1)
2023 and it still works.. ^^^Lati
S
6

Modification of Vale's answer. Separators will not crash this version and they will also be returned ( menuStripItems is a ToolStripItemCollection. ie: this.MainMenuStrip.Items ):

    /// <summary>
    /// Recursively get SubMenu Items. Includes Separators.
    /// </summary>
    /// <param name="item"></param>
    /// <returns></returns>
    private IEnumerable<ToolStripItem> GetItems(ToolStripItem item)
    {
        if (item is ToolStripMenuItem)
        {
            foreach (ToolStripItem tsi in (item as ToolStripMenuItem).DropDownItems)
            {
                if (tsi is ToolStripMenuItem)
                {
                    if ((tsi as ToolStripMenuItem).HasDropDownItems)
                    {
                        foreach (ToolStripItem subItem in GetItems((tsi as ToolStripMenuItem)))
                            yield return subItem;
                    }
                    yield return (tsi as ToolStripMenuItem);
                }
                else if (tsi is ToolStripSeparator)
                {
                    yield return (tsi as ToolStripSeparator);
                }
            }
        }
        else if (item is ToolStripSeparator)
        {
            yield return (item as ToolStripSeparator);
        }
    }

Populate a list:

    List<ToolStripItem> allItems = new List<ToolStripItem>();
    foreach (ToolStripItem toolItem in menuStripItems)
    {
       allItems.Add(toolItem);
       //add sub items
       allItems.AddRange(GetItems(toolItem));
    }

Loop the list:

     foreach(ToolStripItem toolItem in allItems)
     {
          if(toolItem is ToolStripMenuItem)
          { 
             ToolStripMenuItem tsmi = (toolItem as ToolStripMenuItem);
             //Do something with it
          }
          else if(toolItem is ToolStripSeparator)
          {
             ToolStripSeparator tss = (toolItem as ToolStripSeparator);
             //Do something with it
          }
     } 
Spector answered 8/10, 2013 at 21:4 Comment(0)
M
2

It seems you cannot do it with direct 'foreach' approach. I think I figured it out.

List<ToolStripMenuItem> l = new List<ToolStripMenuItem> { };
        l.Add(menuItem1);
        l.Add(menuItem2);

        foreach (ToolStripMenuItem m in l)
        {
            m.Text = "YourTextHere";
        }

Adding menu items manually to a list is a bit barbarian, but using 'foreach' or 'for' or other cycles gave me the same error. something about enumeration. It seems like they cannot count all the menu items by themselves :P On the other hand, if you have items like seperators and other stuff, that is not quite like a simple menu item, putting them all in one list and trying to rename would raise another problem.

This is for changing the text displayed on menu items, but you can do absolutely anything you want with them using this method.

Moneylender answered 13/3, 2013 at 9:21 Comment(3)
That isn't a very dynamic approach, what if I would add a menuItem? I would have to add it in the code too, and that is not what I want.Trifurcate
That's what I said - a barbarian approach, but at least it works :DHeliotherapy
Haha yeah you are right, I will give you +1 for your work and because it does work, but I need to change it dynamically:)Trifurcate
F
1

You've actually got the type wrong, DropDownItems contains a collection of ToolStripItem not a collection of ToolStripMenuItem.

Try this instead:

foreach (ToolStripItem toolItem in menuStrip1.DropDownItems)
{
    //do your stuff
}

Or in your function:

private void SetToolStripItems(ToolStripItemCollection dropDownItems)
{
    foreach (ToolStripItem item in dropDownItems)
    {
        if (item.HasDropDownItems)
        {
            SetToolStripItems(item.DropDownItems);
        }
    }
}
Firn answered 13/3, 2013 at 9:8 Comment(5)
meneStrip1 doesn't contain a DropDownItems collection.Trifurcate
Then use your function and change it to dropDownItemsFirn
@Mobstaa Check my updated edit, I've added a revised version of your function.Firn
There is no ".HasDropDownItems" with item:(Trifurcate
@Mobstaa Doh, they need to be ToolStripMenuItem. What's the error when you run your function? Take out the empty catchFirn
S
1

For .net 4.5 and above I've used this to get dropdownitems for a specific toolstripmenuitem.

foreach (var genreDropDownItem in this.toolStripMenuItem_AddNewShowGenre.DropDownItems)
    {
        if (genreDropDownItem is ToolStripMenuItem) //not a ToolStripSeparator
        {
            ToolStripDropDownItem genreItem = (genreDropDownItem as ToolStripDropDownItem);

            genreItem.Click += toolStripMenuItem_Genre_Click; //add the same click eventhandler to all dropdownitems of parent item this.toolStripMenuItem_AddNewShowGenre
        }
    }
Sidonia answered 16/6, 2015 at 18:29 Comment(0)
P
0

Below is an extension class to get all ToolStripMenuItems. The advantage here is that all code is in one recursive method. One can easily convert this to a generic method if other menu item types are needed.

public static class ToolStripItemCollectionExt
{
    /// <summary>
    /// Recusively retrieves all menu items from the input collection
    /// </summary>
    public static IEnumerable<ToolStripMenuItem> GetAllMenuItems(this ToolStripItemCollection items)
    {
        var allItems = new List<ToolStripMenuItem>();
        foreach (var item in items.OfType<ToolStripMenuItem>())
        {
            allItems.Add(item);
            allItems.AddRange(GetAllMenuItems(item.DropDownItems));
        }
        return allItems;
    }
}
Pseudohermaphrodite answered 5/2, 2015 at 11:23 Comment(0)
D
-1

Please note that "aren't working" is a very inefficient description. You should post the error message or behaviour.

foreach(var item in menuStrip1.Items)
{
 // do something with item... maybe recursively   
}

There is a nice explanation of it here

Diarmit answered 13/3, 2013 at 9:5 Comment(5)
I don't get an error message, but it isn't selecting the right Sub menu Items, what you are doing with your Foreach loop, is just only get the Header of the MenuStrip, but not the dropdownitems.Trifurcate
Did you read the link I provided? It has a full solution to your problem.Diarmit
I used the code of that link, but it isn't working with that method, I will give you a thumbs up for your work, Note: I wasn't the one that down voted you.Trifurcate
Thanks for the thumbs-up. Please note that people cannot help with "it isn't working" if you don't give a more precise description of the problem.Diarmit
It isn't working, because that method is selecting all Menu top items, but I needed the SubItems too, as told in my question:)Trifurcate
C
-1

Here is a very simple solution

foreach (Control Maincontralls in MDIParent1.ActiveForm.Controls) //start it from the form - in this example i started with MDI form
{
    if (Maincontralls.GetType() == typeof(MenuStrip)) // focus only for menu strip
    {
        MenuStrip ms = (MenuStrip)Maincontralls; //convert controller to the menue strip contraller type to access its unique properties

        foreach (ToolStripMenuItem subitem in ms.Items ) // access each items
        {

            if (subitem.Name == "loginToolStripMenuItem") subitem.Text = "Change text in loginToolStripMenuItem";
            //focus controller by its name and access its properties or whatever you wants
        }
        break; //break out the loop of controller of the form coz u don't need to go through other controllers
    }

}
Cryo answered 28/8, 2016 at 7:54 Comment(1)
This will not process the sub items tree at all levels.Culhert

© 2022 - 2024 — McMap. All rights reserved.