【问题标题】:Dynamically filtering a menu (ContextMenuStrip) in C# without recreating the menu?在 C# 中动态过滤菜单(ContextMenuStrip)而不重新创建菜单?
【发布时间】:2012-01-20 16:41:44
【问题描述】:

这可能吗?

我计划有 10 个菜单项,其中将有子菜单项(仅 1 级深)。当用户输入我的TextBox 控件时,我希望能够过滤它们。我知道我可以在第一次打开菜单时过滤项目,但是当类别菜单项没有适用于当前过滤器的子项(通过名称过滤)。

有什么想法吗?

【问题讨论】:

  • 你能不能进入 compentlevel 并根据 TextBox 或它的名称检查它的类型..?
  • 您始终可以禁用不需要的菜单项。在我的应用程序中,我只是动态地创建了菜单。是的,我不再有 Designer 支持,但这很容易做到。唯一让我感到困扰的是菜单确实弹出了至少 10 或 20 像素的正常菜单位置。

标签: c# .net winforms contextmenu contextmenustrip


【解决方案1】:

当您不希望它出现时,将工具条对象的 Visible 属性设置为 false。

【讨论】:

    【解决方案2】:

    例如,我使用 Web 表单应用程序完成此操作

    foreach (Control c in Page.Form.Controls)
                {
                    //Response.Write("WORD2" + c.GetType());
                    if (c is Panel)
                    {
                        foreach (Control p in c.Controls)
                        {
                            if (p is CheckBoxList)
                            {
                                foreach (ListItem li in ((CheckBoxList)p).Items)
                                {
                                    li.Selected = false;
                                }
                            }
                        }
                    }
                }
    

    【讨论】:

    • 感谢 DJ,我不确定您的评论是什么意思,但我不需要检查类型,只需检查菜单项。我会做一些实验。
    • 我的意思是,如果它是一个 TextBox,那么您的 TextBox 控件的类型或名称将被我的带有标签等的示例 CheckListbox 替换...您可以对 MenuItem 进行相同的检查。我给你这个作为一个起点..同样的事情将适用于 windows 窗体只需用 Form.Controls 替换 Page.Form.Controls
    【解决方案3】:

    我添加了一个上下文菜单条 (menuStrip1)。为此,我添加了以下内容:

    File
       Exit
    
    Edit
       Copy
       Paste
           Further Down
    
    Help
       Arghhhh!
    

    然后我添加了一个文本框 (FilterMenuText),并在 OnTextChanged 事件中执行以下操作:

        private void FilterMenuText_TextChanged(object sender, EventArgs e)
        {
    
            foreach (ToolStripMenuItem menuItem in menuStrip1.Items)
            {
                if (menuItem.DropDownItems.Count > 0)
                {
                    bool matchFound = false;
    
                    foreach (ToolStripMenuItem childMenuItem in menuItem.DropDownItems)
                    {
                        if (childMenuItem.Text.ToUpper().Contains(FilterMenuText.Text.ToUpper()))
                        {
                            matchFound = true;
                            break;
                        }
                    }
    
                    menuItem.Visible = matchFound;
    
                }
            }
    
        }
    

    这将根据子菜单项的内容适当地隐藏和显示顶级菜单项。如果您的菜单有多个下拉菜单,请将 foreach 放入递归函数中,例如:

    private void FilterMenuText_TextChanged(object sender, EventArgs e)
    {
    
        foreach (ToolStripMenuItem menuItem in menuStrip1.Items)
        {
            menuItem.Visible = MenuItemHasChildWithName(menuItem, FilterMenuText.Text);
        }
    
    }
    
    
    private bool MenuItemHasChildWithName(ToolStripMenuItem menuItem, string name)
    {
    
        if (!menuItem.HasDropDownItems)
        {
            return false;
        }
    
        bool matchFound = false;
    
        foreach (ToolStripMenuItem childMenuItem in menuItem.DropDownItems)
        {
    
            if (childMenuItem.Text.ToUpper().Contains(name.ToUpper()))
            {
                matchFound = true;
                break;
            }
    
            if (childMenuItem.HasDropDownItems)
            {
                matchFound = MenuItemHasChildWithName(childMenuItem, name);
    
                if(matchFound) { break; }
    
            }
    
        }
    
        return matchFound;
    
    }
    

    【讨论】:

    • 谢谢,这看起来不错。顺便说一句,你为什么使用 ToUpper 而不是 ToLower?
    • 习惯的力量。有些人曾经提到 ToUpper 更快(因此它被用于我曾经参与的项目中),但事实并非如此。 ToUpperInvariant() 已优化,但 ToUpper() 和 ToLower() 是一个选择问题。在可能的情况下,我使用 String.Compare,但在这种情况下,您想查看您输入的字母是否是名称的一部分,因此使用了 Contains 代替。严格来说,IndexOf 可能是结构不变比较的更好选择 (msdn.microsoft.com/en-us/library/dd465121.aspx),但我很懒。
    【解决方案4】:

    这是我用于在上下文菜单上有条件地显示菜单项的方法。如果您使用相同的菜单并且不想显示它,您只需将同一循环中的每个项目设置为 true;

        private void dgViewData_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Right)
            {
                if (dgViewData.HitTest(e.X, e.Y).Type != DataGridViewHitTestType.ColumnHeader)
                {
                    foreach (ToolStripMenuItem menuItem in conMicImport.Items)
                    {
                        menuItem.Visible = menuItem.Text.ToString().Contains("Add") == true ? false : true;
                    }
    
                    conMicImport.Show(dgViewData, e.Location);
                    ctxtDG = dgViewData;
                }
            }
    
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-04-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多