3

I have two click events of menu items in a ContextMenuStrip.
I can get the SourceControl of the clicked context menu item by doing this code:

Control c = ((sender as ToolStripItem).Owner as ContextMenuStrip).SourceControl;

Screenshot of the context menu item

But when I use this code on a context menu item that is in another level it, returns null.

Screenshot of the context menu item in another level

How can I get the SourceControl in the click event of the second screenshot's menu item?

Jimi
  • 29,621
  • 8
  • 43
  • 61
  • It' probably simpler to have a Field (something like `Control CurrentContextMenuOwner`) that is set when a `ContextMenu` is opened. Subscribe the `Opened()` event and set `CurrentContextMenuOwner = (sender as ContextMenuStrip).SourceControl;`. In any of the `ToolStripMenuItems` you can then use the `CurrentContextMenuOwner` reference to access a Control's properties. Set `CurrentContextMenuOwner` to null in the `Closing()` or `Closed()` events of the `ContextMenu`. – Jimi Nov 12 '18 at 12:09
  • This is a bug in the `ContextMenuStrip` that has been there since the beginning, as far as I'm aware. You basically do have to do what @Jimi suggested. You could probably inherit `ContextMenuStrip` and do it internally if you wanted to but, if it's a one-off, a field is the easiest option. – jmcilhinney Nov 12 '18 at 13:11

1 Answers1

2

The ContextMenuStrip SourceControl (the reference of the current Control where the Context Menu is activated) can be retrieved, from a ToolStripMenuItem, inspecting the OwnerItem reference and moving upstream until the OwnerItem reference is null, then inspecting the Owner value, which references the ContextMenuStrip.
(Unfortunately, the SourceControl reference is only available in the ContextMenuStrip control).

A simple alternative method is using a Field that references the Control where the current ContextMenuStrip has been activated (you can have just one active ContextMenuStrip).
This Field reference, set when the ContextMenuStrip is opened - by subscribing to the Opened() event - can then be accessed by any of the ToolStripMenuItem.
The Field reference is then set back to null when then ContextMenuStrip is closed.

▶ Dispose of the contextMenuOwner object when the Form closes.

An example:
(toolStripMenuItem is a generic name, it must be set to an actual control name).

Control contextMenuOwner = null;

private void toolStripMenuItem_Click(object sender, EventArgs e)
{
    contextMenuOwner?.BackColor = Color.Blue;
    //(...)
}

private void contextMenuStrip1_Opened(object sender, EventArgs e)
{
    contextMenuOwner = (sender as ContextMenuStrip).SourceControl;
}

private void contextMenuStrip1_Closed(object sender, ToolStripDropDownClosedEventArgs e)
{
    contextMenuOwner = null;
}
Jimi
  • 29,621
  • 8
  • 43
  • 61
  • Sorry for asking here but how can I get the opposite color of a color? When I have white, black is the opposite and so on... – GoldErzYT GoldErzYT Nov 12 '18 at 16:24
  • `Color OppositeColor = Color.FromArgb(Color.White.ToArgb() ^ 0xffffff);` Simplified. The opposite color depends on color *domain*. It could be much more complex to calculate, depending on the destination. – Jimi Nov 12 '18 at 16:29