ContextMenu Does Not Work?

  • Thread starter Thread starter Mike
  • Start date Start date
M

Mike

Why doesn't the following sample code work? The click event never
seems to fire for the menu items. Similar code works for the
ContextMenuStrip class but I need the modal nature of ContextMenu.

private void ShowContextMenu()
{
using (ContextMenu menu = new ContextMenu())
{
menu.MenuItems.Add("Test1", new EventHandler(MenuItemClicked));
menu.MenuItems.Add("Test2", new EventHandler(MenuItemClicked));
menu.MenuItems.Add("Test3", new EventHandler(MenuItemClicked));

menu.Show(this, new Point(0, 0));
}
}
private void MenuItemClicked(object sender, EventArgs e)
{
MenuItem item = (MenuItem)sender;
MessageBox.Show(item.Text);
}
 
Mike said:
Why doesn't the following sample code work? The click event never
seems to fire for the menu items. Similar code works for the
ContextMenuStrip class but I need the modal nature of ContextMenu.

private void ShowContextMenu()
{
using (ContextMenu menu = new ContextMenu())
{
menu.MenuItems.Add("Test1", new EventHandler(MenuItemClicked));
menu.MenuItems.Add("Test2", new EventHandler(MenuItemClicked));
menu.MenuItems.Add("Test3", new EventHandler(MenuItemClicked));

menu.Show(this, new Point(0, 0));
}
}
private void MenuItemClicked(object sender, EventArgs e)
{
MenuItem item = (MenuItem)sender;
MessageBox.Show(item.Text);
}


Hi Mike,

because (with using) you're calling "menu.Dispose()" directly after you
select one of the menu items. Obviously the ContextMenu is implemented that
way to not fire events after or while disposing. So all you need is to keep
the menu variable on class level.

I think (not tested) it should work, if you only remove the
"using"-statement (and with this "menu.Dispose()"), too because of the
garbage collector and the time needed between closing the menu and fire the
event. So forget everything about that - that's far away from clean code ;)
 
Thanks Wolfgang. That was helpful. It looks like the event gets fired
but the handler doesn't kick in until things are idle. I can either do
what you suggested or add a call to DoEvents before the end of the
using block. Thanks again.
 
I can either do
what you suggested or add a call to DoEvents before the end of the
using block.

NO! Do not use DoEvents. Just put a context menu on your form at design time
and then alter its contents at run time. The system will handle disposing
the menu for you.
 
Thanks for the suggestion Jeff. I only want to use the menu in some
rare situations. Also, where do you set the context menu at design
time? I see context menu strip, but not context menu.

In general, I try to stay away from DoEvents but here it seems like a
valid approach. Why do you think I should avoid it?

As an alternative, I could create the context menu as a member of the
class and dispose it myself when the form/control goes away.
 
Thanks for the suggestion Jeff. I only want to use the menu in some
rare situations. Also, where do you set the context menu at design
time? I see context menu strip, but not context menu.

It should be in the "non-visible controls" area at the bottom of the screen.
When you click on it there it will appear in the menu bar so that you can
modify its items.
In general, I try to stay away from DoEvents but here it seems like a
valid approach. Why do you think I should avoid it?

I don't remember specific reasons, but I've read enough warnings about its
use here to know that it's frowned on in .NET even more so than it was in
Classic VB.
 
Thanks for the suggestion Jeff. I only want to use the menu in some
rare situations. Also, where do you set the context menu at design
time? I see context menu strip, but not context menu.

In general, I try to stay away from DoEvents but here it seems like a
valid approach. Why do you think I should avoid it?

There are a number of good reasons to stay away from DoEvents() and its
relatives generally. But it seems to me that the best reason in this
situation is simply that it doesn't really accomplish what you seem to
hope it would.

Specifically, calling DoEvents() may allow the menu to be drawn, but you
then subsequently dispose the menu right away, before the user gets a
chance to select one of the items in the menu. Even if .NET allows you to
get away with this now, there's certainly no reason it should be
guaranteed to in the long-term. You're just asking for your code to
break, even if for some reason it happens to work now.

Pete
 
Thanks for the input Pete but the issue has nothing to do with drawing
the menu. I think you are confusing this with context menu strip. I am
dealing with a context menu so it acts modal and does not return from
the show function until it is done. The menu gets drawn, I click on an
item, the menu goes away, but no message box appears.
 
Thanks for the input Pete but the issue has nothing to do with drawing
the menu. I think you are confusing this with context menu strip. I am
dealing with a context menu so it acts modal and does not return from
the show function until it is done. The menu gets drawn, I click on an
item, the menu goes away, but no message box appears.

There are a number of good reasons to stay away from DoEvents() and its
relatives generally. But it seems to me that the best reason in this
situation is simply that it doesn't really accomplish what you seem to
hope it would.

Specifically, calling DoEvents() may allow the menu to be drawn, but you
then subsequently dispose the menu right away, before the user gets a
chance to select one of the items in the menu. Even if .NET allows you to
get away with this now, there's certainly no reason it should be
guaranteed to in the long-term. You're just asking for your code to
break, even if for some reason it happens to work now.

Pete


Hi Mike,

I think, Pete is right... Avoid DoEvents wherever it's possible. Yes, it's
easy to use - but as easy it is to use, as easy it is to make things screw
up with DoEvents. It's like the "goto"-Statement. goto really isn't evil
from scratch - quite the opposite. But chances to make things ugly are
really high. Using DoEvents is a valid approach, but you (might) pay much
and get only little.

The bad about DoEvents is, that your UI is kept responsive, what is - in
most cases - also the goal of using it ;)
http://blogs.msdn.com/jfoscoding/archive/2005/08/06/448560.aspx

You also have no guarantee that the disposed object will handle the event
correctly (in future releases of .net). If (on a brand new somewhat-core
processor) the GC is fast enough so you might get an invalid referenced
object in the "sender"-parameter of the event because the MenuItem objects
are disposed with the related ContextMenu object (maybe this is impossible -
I don't know, but I don't want my customers to find out *g*).

It's also a problem/matter of platform independence. Are you really sure,
your program is never ever needed to run on a mono/linux-platform? Have you
tested your solution on all platform constellations (there are many linuxes
out there *g*)? If ever needed, do you remember this "trick" and will you
test this behavior?

My suggestion is: write really clean code, and write it as it should be the
last time you'll do that (what I'm trying to say is: if possible, avoid any
hacks) *g*.

The reason, why ContextMenu can't be dragged to your form is that it's
recommend to replace it with ContextMenuStrip. If you want (I don't
recommandate that), you can get it work as expected. Right click on
Toolbox -> Choose Items... . Then go to tab ".NET Framework Components" (if
not selected) and search "ContextMenu (System.Windows.Forms)" in the list.

My second suggestion is: use ContextMenuStrip ;) It's a replacement (and
enhancement) for ContextMenu.
Why don't you want it? OK, it's not modal (one of the enhancements *g*). But
isn't it better to place the code after ShowContextMenu in MenuItemClicked?
Or listen to the event "menu.Collapse" and place the code there!?

At least - if you've tested it well and it works for you, choose DoEvents.
Yes, it's valid (it's not for nothing in the BCL). Nothing to be ashamed of
;)

Sorry for my bad English (I have to write it every time *g*)
Greets, Wolfgang Kluge
http://gehirnwindung.de/
http://klugesoftware.de/
 
Back
Top