How to Get a ToolStripItem from a Context Menu Click (Right-Click) with ContextMenuStrip

I wanted to display a hierarchical menu for my blog feed reader application. No nesting of categories - just a simple, one-level list with one category at the top and a list of feeds under it. I could have used Treeview control, but Treeview requires custom rendering to display variable font sizes. Blech. I opted instead to use a ToolStrip control with category labels flush against the left, and feeds under the categories displayed as margins. (See the picture from my previous post for a visual.)

I wanted to have a context menu for this "treeview", so that I could add and remove categories and feeds easily. This context menu would need different options - and different actions - depending on what ToolStripItem was underneath the mouse when the user right-clicked.

I thought I could obtain the ToolStripItem underneath the mouse by using the OwnerItem property, as outlined in How to: Handle the ContextMenuStrip Opening Event. No dice. There's no direct ownership between the context menu and the items on the ToolStrip, so this doesn't fly. In order to obtain the ToolStripItem underneath the mouse during right-click, I had to:

  1. Set a ContextMenuStrip for my ToolStrip;
  2. Handle the Opening event on ContextMenuStrip; and
  3. Obtain the ToolStripItem using the GetItemAt() method.

Here's the basic code:

public Form1()
{
InitializeComponent();

toolStrip1.ContextMenuStrip.Opening += new CancelEventHandler(ContextMenuStrip_Opening);
}

void ContextMenuStrip_Opening(object sender, CancelEventArgs e)
{
// This must be relative to the upper left corner of ToolStrip.
Point pt = this.PointToClient(Cursor.Position);
ToolStripItem item = toolStrip1.GetItemAt(pt);
if (item == null)
{
// Offer to add a new category only.
// NOTE: Change this to adjust the menu to your application.
contextMenuStrip1.Items[1].Visible = false;
contextMenuStrip1.Items[0].Visible = true;
}
else
{
// This is a category or a feed.
// NOTE: Change this to adjust the menu to your application.
contextMenuStrip1.Items[0].Visible = false;
contextMenuStrip1.Items[1].Visible = true;
}
}

NOTE: If you debug, do NOT put your breakpoint on the line that calls PointToClient(), as the call to Cursor.Position will return the coordinates of the mouse in the Visual Studio window.