简体   繁体   English

在 ToolStripMenuItem 上添加右键单击上下文菜单,而不关闭菜单

[英]Adding a right-click Context Menu on a ToolStripMenuItem, without closing the Menu

My application has a menu at the top.我的应用程序顶部有一个菜单。
The first item in the menu ( File ) has the usual New , Open... , Save , Save As... as well as Open Recent .菜单中的第一项(文件)具有通常的新建打开...保存另存为...以及打开最近 This last one is a ToolStripDropDown showing a most-recently-used list of filenames.最后一个是 ToolStripDropDown,显示最近使用的文件名列表。

I would like to add a right-click Context Menu (not a sub-menu) to the file names which will have one item in the context menu, to remove the right-clicked filename from the list.我想在上下文菜单中有一项的文件名中添加一个右键单击上下文菜单(不是子菜单),以从列表中删除右键单击的文件名。

I load the file names into the Menu as follows:我将文件名加载到菜单中,如下所示:

private void mnuFile_DropDownOpened(object sender, EventArgs e)
{
    foreach (string fn in mru_files)
    {
        ToolStripMenuItem p = new ToolStripMenuItem(fn);
        p.Click += fn_clicked;
        p.MouseDown += fn_MouseDown;
        openRecentToolStripMenuItem.DropDownItems.Add(p);
    }
}

The main portion of this works fine - the fn_clicked method is invoked when I click on a file and it will do what it's supposed to do.主要部分工作正常 - 当我单击文件时调用fn_clicked方法,它会执行它应该执行的操作。

In the MouseDown Handler I can remove the file from the list as follows:MouseDown处理程序中,我可以从列表中删除文件,如下所示:

private void fn_MouseDown(object sender, MouseEventArgs e)
{
    ToolStripMenuItem toolStripMenuItem = sender as ToolStripMenuItem;

    if (toolStripMenuItem != null
        && e.Button == System.Windows.Forms.MouseButtons.Right
        && mru_files.Find(x => x == toolStripMenuItem.Text) != null)
    {
        mru_files.Remove(toolStripMenuItem.Text);
    }
}

but this doesn't show a menu.但这不显示菜单。

If I add a context menu to the form, and do如果我向表单添加上下文菜单,然后执行

mnu_ctxMRUitem.Show(xyz, e.X, e.Y);

instead of removing the file, I get the Context Menu in the right place, but the original menu with the list of files has disappeared.我没有删除文件,而是在正确的位置获得了上下文菜单,但是带有文件列表的原始菜单已经消失。

How can I show the context menu on right-click of a menu item, without the main menu disappearing.如何在右键单击菜单项时显示上下文菜单,而不会使主菜单消失。

To force a ToolStripDropDown to remain opened, you can set its AutoClose property to false .要强制ToolStripDropDown保持打开状态,您可以将其AutoClose属性设置为false
You can then show a ContextMenuStrip in the location where the right-click was generated.然后,您可以在生成右键单击的位置显示 ContextMenuStrip。

Subscribe to the MouseUp Event of any ToolStripMenuItem that requires a ContextMenuStrip and, if the e.Button == MouseButtons.Right test is positive, block the ToolStripDropDown that is the Owner of the ToolStripMenuItem selected.订阅需要 ContextMenuStrip 的任何 ToolStripMenuItem 的MouseUp事件,如果e.Button == MouseButtons.Right测试为肯定,则阻止作为所选 ToolStripMenuItem 所有者的 ToolStripDropDown。
Use the same MouseUp Event Handler for all ToolStripMenuItems.对所有 ToolStripMenuItem 使用相同的MouseUp事件处理程序。

When the ContextMenuStrip is closed, set the AutoClose property back to true .当 ContextMenuStrip 关闭时,将AutoClose属性设置回true

Of course, you need to perform this operation on all ToolStripDropDown components in the hierarchy, since you may want to activate this functionality to sub-items of a ToolStripMenuItem.当然,您需要对层次结构中的所有 ToolStripDropDown 组件执行此操作,因为您可能希望为 ToolStripMenuItem 的子项激活此功能。
This action is performed by the SetMenutemsAutoClose() method.此操作由SetMenutemsAutoClose()方法执行。

Here, the ToolStripMenuItem that activates the ContextMenuStrip is saved to the [ContextMenuStrip].Tag property.这里,激活 ContextMenuStrip 的 ToolStripMenuItem 被保存到[ContextMenuStrip].Tag属性中。 Feel free to use any other means to store this reference.随意使用任何其他方式来存储此引用。

private void anyToolStripMenuItem_MouseUp(object sender, MouseEventArgs e)
{
    if (e.Button == MouseButtons.Right) {
        var menuItem = sender as ToolStripMenuItem;
        someContextMenuStrip.Tag = menuItem;
        SetMenutemsAutoClose(menuItem, false);
        someContextMenuStrip.Show(MousePosition);
        someContextMenuStrip.Capture = true;
        menuItem.BackColor = Color.FromArgb(42, SystemColors.MenuHighlight);
    }
}

private async void SomeContextMenuStrip_Closed(object sender, ToolStripDropDownClosedEventArgs e)
{
    var cms = sender as ContextMenuStrip;
    if (cms.Tag != null && cms.Tag is ToolStripMenuItem menuItem) {
        // Determine an action based on the ToolStripMenuItem
        Console.WriteLine(menuItem.Name);
        SetMenutemsAutoClose(menuItem, true);
            
        menuItem.BackColor = Color.Transparent;
        // Need to somewhat fight against the internal Timer
        await Task.Delay(100);
        if (menuItem.Owner != null) menuItem.Owner.Capture = true;
    }
}

private void SetMenutemsAutoClose(ToolStripMenuItem menu, bool autoClose)
{
    if (menu == null || menu.Owner == null) return;
    while (menu.Owner is ToolStripDropDown dropDown) {
        dropDown.AutoClose = autoClose;
        menu = dropDown.OwnerItem as ToolStripMenuItem;
    }
}

If Pattern Matching is not available in your version of C#, declare the variable in-line, explictly如果模式匹配在您的 C# 版本中不可用,请显式地内联声明变量

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM