确定使用了ContextMenuStrip的控件


84

我有一个ContextMenuStrip分配给几个不同的列表框。我试图弄清楚ContextMenuStrip什么时候单击了什么ListBox。我尝试从下面的代码开始,但无法正常工作。在sender有正确的价值,但是当我尝试它分配到menuSubmitted它为空。

private void MenuViewDetails_Click(object sender, EventArgs e)
{
    ContextMenu menuSubmitted = sender as ContextMenu;
    if (menuSubmitted != null)
    {
        Control sourceControl = menuSubmitted.SourceControl;
    }
}

任何帮助都会很棒。谢谢。

使用以下帮助,我弄清楚了:

private void MenuViewDetails_Click(object sender, EventArgs e)
        {
            ToolStripMenuItem menuItem = sender as ToolStripMenuItem;
            if (menuItem != null)
            {
                ContextMenuStrip calendarMenu = menuItem.Owner as ContextMenuStrip;

                if (calendarMenu != null)
                {
                    Control controlSelected = calendarMenu.SourceControl;
                }
            }
        }

感谢您寻找的解决方案。我有同样的问题。但是我建议不要嵌套所有这些if语句,if (menuItem == null) return;如果您像我一样,并且不希望将处理该语句的代码嵌套不必要的2个层次,请不要使用它们。
肖恩·科瓦奇

Answers:


123

为一个 ContextMenu

问题是sender参数指向项目单击的上下文菜单上,而不是上下文菜单本身。

不过,这是一个简单的修复方法,因为每个方法MenuItem公开了一个GetContextMenu方法,该方法将告诉您哪个ContextMenu包含该菜单项。

将您的代码更改为以下内容:

private void MenuViewDetails_Click(object sender, EventArgs e)
{
    // Try to cast the sender to a MenuItem
    MenuItem menuItem = sender as MenuItem;
    if (menuItem != null)
    {
        // Retrieve the ContextMenu that contains this MenuItem
        ContextMenu menu = menuItem.GetContextMenu();

        // Get the control that is displaying this context menu
        Control sourceControl = menu.SourceControl;
    }
}

对于ContextMenuStrip

如果使用aContextMenuStrip而不是a,它的确会稍有改变ContextMenu。这两个控件彼此不相关,并且一个实例不能转换为另一个实例。

和以前一样,被单击的项目仍会在sender参数中返回,因此您必须确定ContextMenuStrip拥有该单独菜单项的。您可以使用该Owner属性。最后,您将使用该SourceControl属性来确定哪个控件正在显示上下文菜单。

像这样修改您的代码:

private void MenuViewDetails_Click(object sender, EventArgs e)
{
     // Try to cast the sender to a ToolStripItem
     ToolStripItem menuItem = sender as ToolStripItem;
     if (menuItem != null)
     {
        // Retrieve the ContextMenuStrip that owns this ToolStripItem
        ContextMenuStrip owner = menuItem.Owner as ContextMenuStrip;
        if (owner != null)
        {
           // Get the control that is displaying this context menu
           Control sourceControl = owner.SourceControl;
        }
     }
 }

@bluefeet:那你还有其他问题。我只是用三个不同的列表框测试了此代码,并且一切正常。发布更多repro代码。
科迪·格雷

2
@bluefeet:我已经更新了答案中的代码。ContextMenu和之间有很大的区别ContextMenuStrip。(嗯,我看您已经知道了。嗯,最好是自己学习!)
科迪·格雷

1
我使用Opening事件记录了将菜单打开到局部变量的SourceControl,然后在处理项目单击时引用了该控件。
QuickDanger 2017年

1
@QuickDanger呀,SourceControl可悲的是空的时刻一个Click一个的事件ToolStripItem的子项ContextMenuStrip被触发。似乎ContextMenuStripClosed事件Click事件之前触发,这可能是导致问题的原因。我假设该属性在菜单“关闭”之后被清除。
Nyerguds

1
@CodyGray实际上,如果树更深,则必须循环OwnerItem属性链,直到找到其属性ToolStripItem中具有的为止。但是,正如我刚刚评论的那样,它是行不通的。在上下文菜单上的将是无效的。您说过您无法重现它...也许问题只在菜单深于一层的情况下才会发生?我的是深两个子级别的。ContextMenuStripOwnerSourceControl
Nyerguds

3

较早的帖子,但万一像我这样的人遇到了它:

对于ContextMenuStrip,以上内容对我而言不起作用,但是它导致了查找。

void DeleteMenu_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
{
    ContextMenuStrip menu = sender as ContextMenuStrip;
    Control sourceControl = menu.SourceControl;
    MessageBox.Show(sourceControl.Name);
}

这给了我预期的控件名称。您可以使用if语句进行验证等,我只是发布来说明这一点。


这仅适用于中的直接项目ContextMenu。问题是ItemClicked单击子菜单项时不会触发;他们需要自己的Click事件,该事件会将项目本身作为发送者,而不是菜单。
Nyerguds

3

我很难让这些代码正常工作。这是我能找到的最简单的解决方案:

对于ContextMenuStrip:

    Control _sourceControl = null;
    private void contextMenuStrip_Opened(object sender, EventArgs e)
    {
        _sourceControl = contextMenuStrip.SourceControl;
    }

    private void contextMenuItem_Click(object sender, EventArgs e)
    {
        var menuItem = (ToolStripMenuItem)sender;

        _sourceControl.Text = menuItem.Text;
        MessageBox.Show(menuItem.Name);
        MessageBox.Show(sourceControl.Name);
    }

0

最简单的解决方案是:

Control parentControl = ((sender as MenuItem).GetContextMenu()).SourceControl;
 
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.