tags:

views:

232

answers:

2

I'm using the following code to display a context menu on my form when someone presses "Alt-A":

private void Form1_KeyDown(object sender, KeyEventArgs e)
{
    if (e.Alt && e.KeyCode == Keys.A)
    {
        ContextMenuStrip  menu = new ContextMenuStrip();
        ToolStripMenuItem item = new ToolStripMenuItem("Hello &World");
        item.Click += new EventHandler(item_Click);
        menu.MenuItems.Add(item);

        ToolStripMenuItem item2 = new ToolStripMenuItem("Some &Andriod");
        item2.Click +=new EventHandler(item_Click);
        menu.MenuItems.Add(item2);

        menu.Show(this, new Point(0,0));
    }
}

void item_Click(object sender, EventArgs e)
{
    MessageBox.Show("Hey!")
}

The problem I'm having is that the second meny item ("Some &Android") is being "Clicked" immediately as soon as the menu is displayed - apparently because the keypress (Alt-A) is being immeditely passed to the menu.

If I change that menu item to have a different Mnemonic (e.g. "&Some Android") then this doesn't happen and the menu is displayed as normal.

I know that the ContextMenu class is deprecated, but is there any way of preventing this behaviour? I've already tried setting the Handled property of the EventArgs to true, but that did nothing (presumably because that wont do anything until the event handler completes, and the Show() method halts execution until the ContextMenu is no longer displayed.

UPDATE: I've updated the code to use the newer ContextMenuStrip class and found that the same thing happens, however the ContextMenuStrip class provides a lot more methods for me to override allowing better control of the menu item.

I've noticed that with the ContextMenuStrip class the Show() method returns instantly (while the menu is still displayed), however even setting the Handled property on the event args to true does not prevent the key press being handled by the context menu.

I'm looking into using some more complex logic to decide whether or not to fire the click event based on if a certain time interval has passed since the menu was shown, and if a KeyUp event has been processed since then, but it all seems extremely messy - surely someone else has run into this problem before?

+1  A: 

I think this might be more related to the fact that in KeyDown you open your menu and KeyUp gets passed to the menu then instead.

So you should perhaps move the menu opening to KeyUp or KeyPress. This should avoid the problem entirely then.

Joey
That did the trick - thanks.
Kragen
Hmmm, possibly I was a little hasty - yes putting the same logic into the KeyUp event prevents this, however ideally I want to have the menu shown during KeyDown - also the menu is triggered before I release any keys, (so I dont know if this is the key up event being triggered)
Kragen
Hm, then I think you should try figuring out *what* exactly happens, by registering event handlers for KeyUp/Down on the menu and your form and printing appropriate diagnostic messages. Right off the top of my head I don't know what exactly might be responsible here. If `e.Handled = true` doesn't help it smells like it's either KeyPress or KeyUp which triggers the menu entry.
Joey
I've added handlers for KeyPress and KeyUp to my form, however none of these get fired. I've also overridden the ProcessCmdKey method on MenuItem and that also doesn't get fired - I cant think of any other keypress related methods or events to attach to.
Kragen
Hmm, then I don't know, sorry.
Joey
I think I'm going to have to re-implement using ContextMenuStrip and use some logic to filter out this key event being raised - I'm marking this as accepted as it did fix the problem (but having the menu appear on KeyUp feels nasty in the UI)
Kragen
+1  A: 

Hi,

I had the same problem with a pressed Alt key while opening a context menu. I figured out that it was the key event inside the context menu which released it shortly after creation. I solved the problem by inheriting the contextmenustrip and overriding the ProcessCmdKey method as follows:

public partial class AdvancedContextMenuStrip : ContextMenuStrip
{
    public AdvancedContextMenuStrip()
    {
        InitializeComponent();
    }

    protected override bool ProcessCmdKey(ref Message m, Keys keyData)
    {
        if ((keyData & Keys.Alt) == Keys.Alt)
            return true;

        return base.ProcessCmdKey(ref m, keyData);
    }
}
Sven