4
votes

This might be incredibly simple and I'm not seeing it because it's the end of a long day, and if it is I apologize in advance.

I've got a set of Buttons that when right-clicked pop up a ContextMenu. The menu has two MenuItems, both of which have a Click handler function assigned. I'm triggering the ContextMenu to pop up on the right click of a button like so:

Overly simplified example:


public void InitiailizeButtonContextMenu()
{
    buttonContextMenu = new ContextMenu();
    MenuItem foo = new MenuItem("foo");
    foo.Click += OnFooClicked;

    MenuItemCollection collection = new MenuItemCollection(buttonContextMenu);
    collection.Add(foo);
}

public void OnButtonMouseClick(object sender, MouseEventArgs e)
{
    if (e.Button == MouseButtons.Left)
        // left click stuff handling
    if (e.Button == MouseButtons.Right)
        buttonContextMenu.Show((Button)sender, new Point(e.X, e.Y));
}


public void OnFooClicked(object sender, EventArgs e)
{
    // Need to get the Button the ContextMenu .Show'd on in
    // OnButtonMouseClick...  thoughts?
}


ContextMenu buttonContextMenu; 

I need to be able to get the Button that triggered the ContextMenu to pop up IN the Click handler for the MenuItem, or get it to it somehow. MenuItem.Click takes EventArgs, so nothing useful there. I can cast object sender back to MenuItem but I can't find anything that tells me what made it pop up. Is this possible?

6
Is this a WinForms or WPF question?Chuck Savage

6 Answers

7
votes

Use the ContextMenu.SourceControl property, it gives you a reference to the Button instance back.

2
votes

In the above code excerpt, when you call the show method of buttonContextMenu, you pass the button object to buttonContextMenu when you right-click on the button.

To access the button in the OnFooClicked method simply cast the 'sender' back to a button.

public void OnFooClicked(object sender, EventArgs e)
{
     ((MenuItem)sender).Parent //This is the button
}

*I don't know if MenuItem is the correct cast but it should be along those lines.

2
votes

If you are using ContextMenuStrip and ToolStripItem, rather than ContextMenu and MenuItem, you'll need:

private void myToolStripMenuItem_Click(object sender, EventArgs e)
{
   Button parent = (Button)((ContextMenuStrip)((ToolStripItem)sender).Owner).SourceControl;
   ...

With a regular ContextMenu and MenuItem (from trycatch's comment on Hans Passant's post):

Button parent = (Button)((ContextMenu)((MenuItem)sender).Parent).SourceControl; 
0
votes


Button buttonThatTriggeredTheContextMenu; 

public void OnButtonMouseClick(object sender, MouseEventArgs e)
{
    if (e.Button == MouseButtons.Left)
        // left click stuff handling
    if (e.Button == MouseButtons.Right) {
        buttonThatTriggeredTheContextMenu = (Button)sender;
        buttonContextMenu.Show((Button)sender, new Point(e.X, e.Y));
    }
}


public void OnFooClicked(object sender, EventArgs e)
{
    //buttonThatTriggeredTheContextMenu contains the button you want
}

0
votes

I'm not 100% on this - its from code I wrote about 2 years ago, but I hope it gets you moving on this.

MenuItem item = (MenuItem)sender;
DependencyObject dep = item.Parent;
while((dep != null) && !(dep is Button))
    dep =  VisualTreeHelper.GetParent(dep);

if (dep == null)
    return;
Button button = dep as Button;
0
votes
button mybutton = ((ContextMenu)((MenuItem)sender).Parent).SourceControl as button;