2

I want to put a context sensitive menu on the right-click of a DataGridView. I want to have a single menu item derived from the content of the clicked cell and a variable number of items in a sub-menu, retrieved from a database.

I do this by building the ToolStripMenuItem in the ContextMenuStrip Opening event. And it works - almost...

If I leave the sub-menu undisplayed so the user has to click the single item in the toplevel menu, everything is fine but if I call the ShowDropDown method to display the submenu automatocally, the exents don't fire when the items are clicked on.

Here's the simplest code I can produce to recreate the problem - I've pulled out all the references to the DataGridView and database so my "dynamic" menu is decidedly static ;-)

If you put this is a Form definition, right-click anywhere on the form and you'll see the working but not desired behaviour - click on a sub-menui tem and see a popup. Tick the checkbox and right-click again and you'll see the submenu flies out automatically - but clicking items won't fire the aliasClick handler.

Any thoughts? In this particular application, I can code a perfectly servicable workaround which avoids using ShowDropDown - but I'd like to know what I'm doing wrong in case I need to use it in future.

public partial class Form1 : Form
{
    private ContextMenuStrip cms;
    private CheckBox chkAuto;

    public Form1()
    {
        InitializeComponent();

        chkAuto = new CheckBox();
        Controls.Add(chkAuto);

        cms = new ContextMenuStrip();
        cms.Opening += contextMenuStrip1_Opening;

        this.MouseClick += Form1_MouseClick;
    }

    private void Form1_MouseClick(object sender, MouseEventArgs e)
    {
        if (e.Button == System.Windows.Forms.MouseButtons.Right)
            cms.Show(Cursor.Position);
    }

    private void contextMenuStrip1_Opening(object sender, CancelEventArgs e)
    {
        cms.Items.Clear();
        ToolStripMenuItem tsmi = new ToolStripMenuItem("Title from datagridviewcell");
        tsmi.DropDownItems.Add(new ToolStripMenuItem("First item from database lookup", null, aliasClick));
        tsmi.DropDownItems.Add(new ToolStripMenuItem("Second item from database lookup", null, aliasClick));
        tsmi.DropDownItems.Add(new ToolStripMenuItem("Last item from database lookup", null, aliasClick));
        cms.Items.Add(tsmi);
        if (chkAuto.Checked)
            tsmi.ShowDropDown();
        e.Cancel = false;
    }
    private void aliasClick(object sender, EventArgs e)
    {
        ToolStripMenuItem clickedItem = (ToolStripMenuItem)sender;
        MessageBox.Show(clickedItem.Text);
    }
}

1 Answers1

0

I'm not entirely sure how to go about proving this, but I suspect that your call to tsmi.ShowDropDown() is somehow causing the coordinates to not be captured properly by the click handler. Replace it with cms.Show(MousePosition) and it works.

Perhaps some useful info gleaned from a look at the coordinates...

var mi = new ToolStripMenuItem("First item from database lookup", null, aliasClick);
tsmi.DropDownItems.Add(mi);
var mi2 = new ToolStripMenuItem("Second item from database lookup", null, aliasClick);
tsmi.DropDownItems.Add(mi2);
var mi3 = new ToolStripMenuItem("Last item from database lookup", null, aliasClick);
tsmi.DropDownItems.Add(mi3);
cms.Items.Add(tsmi);
if (chkAuto.Checked)
    tsmi.ShowDropDown();
    //cms.Show(MousePosition);
Debug.WriteLine(mi.Bounds.ToString());
DonBoitnott
  • 10,787
  • 6
  • 49
  • 68
  • I've had a quick tinker but although `cms.Show()` does preserve the event handler, it doesn't (as far as I can tell) cause the sub-menu to open automatically. I suspect you're right about the coordinates - but I don't know what to do about it! – Dwauctioneer Jul 11 '17 at 20:00
  • Curious. In my test app, the menu opens as expected. – DonBoitnott Jul 12 '17 at 10:41
  • It'll open if you hover over the top-level item or click it, but for me it doesn't open otherwise. It may be easier to spot if you make the cms open away from the mouse: `private void Form1_MouseClick(object sender, MouseEventArgs e) { if (e.Button == System.Windows.Forms.MouseButtons.Right) cms.Show(new Point(Cursor.Position.X + 50, Cursor.Position.Y + 50)); }` I've tried it at home on the free version of VS Express and at work on VS Pro 2015 – Dwauctioneer Jul 13 '17 at 15:32