Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c# WinForms - Keep a ContextMenu from closing after a click on certain Items

Tags:

c#

contextmenu

I'm using System.Windows.Forms.ContextMenu. I want to make it so when you click some of the buttons, it doesn't close the menu. Right now I have it working where whenever you click one, it will reopen the menu at the same position. The only problem is it looks bad because you can see the menu flicker. Is there any better way to do this?

WPF's ContextMenu has the StaysOpen property, but the Win Forms one doesn't. (Is there any way I can use WPF's ContextMenu?) I don't want to use ContextMenuStrip, which can do this, because the ContextMenu looks a lot nicer.

Edit:

I'm not going to mark this as a solution because it's not good to do this. If you need to do what my question asks, one way would be to make a UserControl from WPF, and then put the object with the context menu in it, then add the context menu to that. Now because it's in WPF, on the buttons you don't want to close the menu on click, set the property StaysOpenOnClick to true on the MenuItem. Then just put this UserControl into your WinForms app.

like image 501
cat Avatar asked Jul 25 '12 20:07

cat


2 Answers

You can keep your context menu open like this:

private bool CloseContextMenu = true; //Class Variable

Then add the MouseDown even to your context menu item:

private void menu1ToolStripMenuItem_MouseDown(object sender, MouseEventArgs e)
{
    CloseContextMenu = false;
}

Then on your context menu closing event:

private void contextMenuStrip1_Closing(object sender, ToolStripDropDownClosingEventArgs e)
{
    e.Cancel = !CloseContextMenu;
    CloseContextMenu = true;
}

Then you can add the CloseContextMenu = false to any of the menu events that you want.

Hope this helps.

like image 168
CodeLikeBeaker Avatar answered Nov 15 '22 04:11

CodeLikeBeaker


There's no good way to do this using a ContextMenu control. That one is just a wrapper around the native Win32 menus, which is why it looks so much better. Its drawn using the OS APIs, just like the menus in all other applications.

Compare that to the ContextMenuStrip control, which is completely custom drawn by the framework in C# code. It looked super cool (I guess) back when it was first released, when Windows and Office XP were the newest products on the shelves. When Windows Vista rolled out, it became horribly obsolete. The only advantage it does have is that you have a lot more fine-grained control over the menus. For example, you can host custom controls in the menus, and you can prevent the menu from closing when you click on one of the items. The native Win32 menus don't have support for that.

Of course, it's more than just an oversight or accidental omission. The desire to keep a context menu open after the user has already selected something is a good clue that your design is wrong. Keep in mind that the purpose of a context menu is to give the user fast access to contextually-relevant options. All they have to do is right-click (or press a special button on their keyboard), and they can see a menu of choices directly related to what they're working on or trying to accomplish. Just like a regular menu, they're supposed to be able to select an option and have the menu go away.

In Windows, all menus are "auto-close". If the menu should be persistent, it shouldn't be a menu at all. Consider using a toolbar, a side bar, or some type of custom control instead. Those aren't designed to go away when one of their options are selected, and therefore they're ideal for showing related options that should always be visible.

If a context menu in an application didn't go away after I selected an option, I'd consider that to be a bug. At the very least, I'd assume that my selection didn't "take" and try clicking it again.

I haven't the slightest clue why the WPF team decided to provide a StaysOpen option for their context menus, or why they rewrote their own context menu class in the first place. Didn't they learn something from the WinForms team having already done the same thing?

The only way to do what you're asking with the ContextMenu control (and therefore the native menus) is a hack similar to that which you describe—store the previous position of the menu, and after a command has been selected, reshow the pop-up menu in its previous location. Whatever cure you come up with for the flicker (e.g., freezing the screen and suppressing repaints until the context menu is reshown) is almost guaranteed to be worse than the disease.

like image 42
Cody Gray Avatar answered Nov 15 '22 03:11

Cody Gray