在MenuStrip中对每个子项进行循环

7
我想获取我的 MenuStrip 的所有 SubItems,这样我就可以一次性更改它们。
我尝试类似以下的方法,但它们并没有起作用:
foreach (ToolStripMenuItem toolItem in menuStrip1.DropDownItems)
{
      //Do something with toolItem here
}

有人能帮忙编写一个好的foreach循环,以便从MenuStrip中获取所有的SubMenuItems(DropDownItems)吗?

编辑:现在尝试使用以下递归方法

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
            {

            }
        }

提示:您需要使用递归。 - Vale
我正在尝试寻找一个好的文章... - Max
4
obj.GetType().Equals(typeof(ToolStripMenuItem)) 可以简单地写成 (obj is ToolStripMenuItem)。 - Vale
8个回答

7

试试这个:

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;
    }
}

2023 年仍然可以运行... ^^^ - user1853517

6

修改Vale的答案。分隔符不会导致该版本崩溃,并且它们也将被返回(menuStripItems是ToolStripItemCollection。即: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);
        }
    }

填充列表:

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

循环列表:

     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
          }
     } 

2

看起来您不能使用直接的“foreach”方法完成它。我想我已经想出来了。

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

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

手动添加菜单项有点原始,但使用'foreach'或'for'或其他循环方法会出现相同的错误。似乎它们无法自己计算所有菜单项:P 另一方面,如果您有像分隔符和其他东西这样的项,那不太像一个简单的菜单项,把它们全部放在一个列表中并尝试重命名会引起另一个问题。
这是为了更改菜单项上显示的文本,但您可以使用此方法对其进行任何想要的更改。

这不是一个非常动态的方法,如果我添加了一个菜单项怎么办?我也必须在代码中添加它,这不是我想要的。 - Max
这就是我说的 - 一种野蛮的方法,但至少它能够工作 :D - Mārtiņš Radiņš
哈哈,是的,你说得对。我会给你加一分,因为你的代码确实可行。但是我需要让它动态地改变 :) - Max

1

对于 .net 4.5 及以上版本,我使用以下代码获取特定工具栏菜单项的下拉选项:

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
        }
    }

1
你实际上是类型错误了,DropDownItems包含一个ToolStripItem的集合,而不是ToolStripMenuItem的集合。

请尝试使用以下内容:

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

或者在你的函数中:

private void SetToolStripItems(ToolStripItemCollection dropDownItems)
{
    foreach (ToolStripItem item in dropDownItems)
    {
        if (item.HasDropDownItems)
        {
            SetToolStripItems(item.DropDownItems);
        }
    }
}

meneStrip1不包含DropDownItems集合。 - Max
然后使用您的函数并将其更改为“dropDownItems”。 - Mathew Thompson
@Mobstaa,请检查我的更新编辑,我已经添加了您的函数的修订版本。 - Mathew Thompson
该项中没有“.HasDropDownItems”:( - Max
@Mobstaa 哦,它们需要是 ToolStripMenuItem。当您运行函数时出现了什么错误?去掉空的 catch - Mathew Thompson

0
以下是一个扩展类,用于获取所有的ToolStripMenuItem。这里的优点是所有的代码都在一个递归方法中。如果需要其他菜单项类型,可以很容易地将其转换为通用方法。
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;
    }
}

-1

这里有一个非常简单的解决方案

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
    }

}

这将不会处理所有级别的子项树。 - stigzler

-1
请注意,“aren't working”是非常低效的描述。您应该发布错误消息或行为。
foreach(var item in menuStrip1.Items)
{
 // do something with item... maybe recursively   
}

这里有一个很好的解释在这里


我没有收到错误信息,但它没有选择正确的子菜单项。你在Foreach循环中所做的只是获取MenuStrip的标题,而不是下拉菜单项。 - Max
你看了我提供的链接吗?它有你问题的完整解决方案。 - nvoigt
我使用了链接中的代码,但它与该方法不兼容,我会给你一个赞,注意:我不是那个给你点踩的人。 - Max
谢谢点赞。请注意,如果您没有更精确地描述问题,人们无法帮助解决“它不起作用”的问题。 - nvoigt
这个方法不起作用,因为它只选择了所有菜单顶部的项目,但是我还需要子项目,就像我在问题中提到的一样:) - Max

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接