ContextMenuStrip.Owner Property null When Retrieving From Nested ToolStripMenuItem

I have a ContextMenuStrip setup with two ToolStripItems. The second ToolStripItem has two additional nested ToolStripItems. I define this as:

ContextMenuStrip cms = new ContextMenuStrip();
ToolStripMenuItem contextJumpTo = new ToolStripMenuItem();
ToolStripMenuItem contextJumpToHeatmap = new ToolStripMenuItem();
ToolStripMenuItem contextJumpToHeatmapStart = new ToolStripMenuItem();
ToolStripMenuItem contextJumpToHeatmapLast = new ToolStripMenuItem();

cms.Items.AddRange(new ToolStripItem[] { contextJumpTo,
                                         contextJumpToHeatmap});
cms.Size = new System.Drawing.Size(176, 148);

contextJumpTo.Size = new System.Drawing.Size(175, 22);
contextJumpTo.Text = "Jump To (No Heatmapping)";

contextJumpToHeatmap.Size = new System.Drawing.Size(175, 22);
contextJumpToHeatmap.Text = "Jump To (With Heatmapping)";
contextJumpToHeatmap.DropDownItems.AddRange(new ToolStripItem[] { contextJumpToHeatmapStart, 
                                                                  contextJumpToHeatmapLast });

contextJumpToHeatmapStart.Size = new System.Drawing.Size(165, 22);
contextJumpToHeatmapStart.Text = "From Start of File";

contextJumpToHeatmapLast.Size = new System.Drawing.Size(165, 22);
contextJumpToHeatmapLast.Text = "From Last Data Point";

I then setup an event listener for the click events of the three ToolStripMenuItems that I want to respond to. Here are the methods (I only listed two of the three methods):

void contextJumpTo_Click(object sender, EventArgs e)
{
    // Try to cast the sender to a ToolStripItem 
    ToolStripMenuItem menuItem = sender as ToolStripMenuItem;
    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 
            DataGridView dgv = owner.SourceControl as DataGridView;
            if (dgv != null)
                // DO WORK
        }
    } 
}

void contextJumpToHeatmapStart_Click(object sender, EventArgs e)
{
    // Try to cast the sender to a ToolStripItem 
    ToolStripMenuItem menuItem = sender as ToolStripMenuItem;
    if (menuItem != null)
    {
        // Retrieve the ToolStripItem that owns this ToolStripItem 
        ToolStripMenuItem ownerItem = menuItem.OwnerItem as ToolStripMenuItem;
        if (ownerItem != null)
        {
            // Retrieve the ContextMenuStrip that owns this ToolStripItem 
            ContextMenuStrip owner = ownerItem.Owner as ContextMenuStrip;
            if (owner != null)
            {
                // Get the control that is displaying this context menu 
                DataGridView dgv = owner.SourceControl as DataGridView;
                if (dgv != null)
                    // DO WORK
            }
        }
    }
}

Here is the issue I have:

My contextJumpTo_Click method works perfectly fine. We get all the way down to where I determine which DataGridView the click came from and I can proceed. The contextJumpTo ToolStripMenuItem is, however, NOT a nested menu item on the ContextMenuStrip.

But my method for contextJumpToHeatmapStart_Click does not work right. When I get down to the line where I determine owner.SourceControl, the SourceControl is null and I cannot proceed. Now I know that this ToolStripMenuItem is nested under another one in my ContextMenuStrip, but why is the SourceControl property suddently null on my ContextMenuStrip?

How do I obtain the SourceControl for a nested ToolStripMenuItem for a ContextMenuStrip?


I believe that's a bug.

I tried to crawl up the list of toolstrip parents to get to the ContextStripMenu owner, which worked, but the SourceControl property was always null.

It looks like the common work around is to set the control on the opening of the context menu:

private Control menuSource;

cms.Opening += cms_Opening;

void cms_Opening(object sender, CancelEventArgs e) {
  menuSource = ((ContextMenuStrip)sender).SourceControl;
}

Then your code basically turns into this:

DataGridView dgv = menuSource as DataGridView;
if (dgv != null) {
  // do work
}