Click here to Skip to main content
Email Password   helpLost your password?

Sample context menu without XP theme applied

Figure 1.

Sample menu with XP theme applied

Figure 2.

Introduction

No need to say that many of us tried to decorate downcast appearance of standard menus. And so did I. First of all, I tried to find something suitable amongst already written code. And the best code that I've found belongs to Chris Beckett: Menu Images using C# and IExtenderProvider - a better mousetrap!, published on The Code Project.

Then I tried to make the code a bit more flexible: enable owner drawing for some menu items, not all, allow to use custom fonts for menu text and make an ImageIndex selector for VS Designer. Although not all problems were solved - I'll say about it below - you can use this code and I hope to improve it.

Using the MenuExtender

Because this article has appeared as a remaking of Chris' MenuImageLib class, I refer you to his article if you wish to know how to extend standard class behavior with IExtenderProvider. He clearly demonstrates how to add owner drawn menus without overriding OnMeasureItem and OnDrawItem for every menu item.

My version of the MenuExtender provides following properties to the MenuItem:

The MenuExtender is applicable for non-top menu items and context menus. In order to use it in your project, add it to your VS toolbox:

That will add a "MenuExtender" icon to the Windows Forms tab. Drag this icon to your form. By this action, you will add the MenuExtender component to your project:

    private MenuExtender.MenuExtender menuExtender;
    // :

    this.menuExtender = new MenuExtender.MenuExtender(this.components);

Now you should set some properties for the MenuExtender. Using the Properties window, set an ImageList (if you have one) with images for icons on your menu items:

Figure 3.

If SystemFont is true, it means that texts on your menus will be displayed with the SystemInformation.MenuFont. If you wish to use some other font - just select it for the Font property and set SystemFont to false. That will generate the following code:

    this.menuExtender.Font = new System.Drawing.Font("Tahoma", 9.75F, 
        System.Drawing.FontStyle.Regular, 
        System.Drawing.GraphicsUnit.Point, 
        ((System.Byte)(204)));
    this.menuExtender.ImageList = this.imageList;
    this.menuExtender.SystemFont = false;

But I don't advice to do it in the beginning of your application. If a user's computer doesn't have the specified font installed - you'll get an exception. You can write this piece of code somewhere in "Customize your application" class. If you have already set some font and wish to return to default settings - right-click on the "Font" field and select "Reset".

And, at last, we can tune our menu items. Select one and find the "Menu Extender" category in the Property window:

Figure 4.

If ExtEnable is true - the menu item will be drawn by the MenuExtender. The ImageIndex is the index of the image item in the ImageList associated with the MenuExtender. Pay attention to OwnerDraw property - it is set to true automatically. Final code for a menu item looks like the following:

    this.menuExtender.SetExtEnable(this.menuItem4, true);
    this.menuExtender.SetImageIndex(this.menuItem4, 2);
    this.menuItem4.OwnerDraw = true;

Now it's time to start the engine! Compile the test project and run it.

Tips & Tricks

If you compare the menu separators on Figure 1 and Figure 2, you can see that the left separator has a custom 3D look. It's because the MenuExtender was not enabled for this separator. I think it's better than to track XP theme switching.

Known Problems

I've found one serious limitation - this class cannot be used in a MDI application. The reason lies out of my class - it's a common problem for the framework. You can easily ascertain that your owner drawn menu items in a MainMenu of a MDI parent form can disappear. Create a MDI child form with its own menus added/merged to the parent. Open a few child forms and close them. Look at your MainMenu with owner drawn items - they are blank. The similar problem with owner drawn menus attached to a NotifyIcon component is described in the Knowledge Base article 827043.

Acknowledgements

I used a great many sources for my work. But the first one was Menu Images using C# and IExtenderProvider - a better mousetrap! by Chris Beckett.

Another good resource is Dino Esposito's article in the MSDN Magazine - Cutting Edge: Owner-Drawing in .NET.

History

February 23rd, 2004 - First release.

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
RantFont change does not apply to all
Member 1457985
23:47 23 Jun '09  
I tried adapting the code to change the font of the Menu. But found that the top level MenuItem objects (menuItem.Parent == MainMenu) are not Drawn by the extenderFrown . The MenuItem and associated drawing does a lot more, a) on pressing Alt the the first menu gets highlighted b) on hover the top level menu item on which the mouse hovers gets highlited.

So if you are planning to just change the Font to adhere to the standard of the entire application this will not work.

rv

GeneralAdding menu items dynamically in vb6
S.M..kanerkar
2:39 17 Jan '09  
hi,

i want to add menues dynamically in vb6. pls tell me how to do it. i don't have any idea regarding this.

thanks
GeneralTo install sql server 2000 on vista
S.M..kanerkar
2:33 17 Jan '09  
hi,
good afternoon,

While installing sql2000 on windows vista, system giving error
'INSTALL SHIELD ENGINE HAS STOPPED WORKING'

HOW CAN I INSTALL SQL ON VISTA?
GeneralExtEnable = True Default for ALL items
Mr.Jinky
0:42 31 Jul '08  
How do I make the ExtEnable automatically be set to True by default?

-= Really cool sig goes here =-

QuestionProblems doing menuExtender.SetExtEnable(item, false)
Manfred Weigl
6:24 27 Aug '07  
Hi,

we've been using MenuExtender to draw images in our menus. All worked fine and we were very happy with this great tool.
Now I want to add context menus to our app, cloning parts of the existing main menu. We don't want to show images in the context menu, so I tried to call SetExtEnable(.., false), but this does not seem to work for me.
To simplify the problem, I called SetExtEnable(.., true) on the items in the main menu, then SetExtEnable(.., false) on some of them. Here again, the images keep being displayed, instead of being hidden, as I expected. The calls go to the same MenuExtender object.
Can anybody give me a hint what I am doing wrong?

Thanks in advance,
Manfred.

mw@branchware.de
GeneralI can't found MenuExtender.dll
rooh572001
0:36 6 Feb '07  
Hi
please help me to found MenuExtender.dll
thanks
Generaldon't work in trayicon context menu
Deemc
7:09 29 Jan '07  
don't work in trayicon/nofifyIcon context menu
Confused no draw
Confused no string
GeneralRe: don't work in trayicon context menu
Deemc
8:44 29 Jan '07  
Big Grin BetterMenu 1.5.0.0
Download at : http://www.misterdotnet.com/blog/?cat=19
NotifyIcon fix to support owner draw menus in .NET 1.x

GeneralMenuExtender Right-To-Left
czaval
23:33 28 Oct '06  
Hi Eugene,

Thank you very much for your MenuExtender,very usefull.

For converting it to 'Right-To-Left'I think there is a need to change functions for drawing the text, icon and etc. I tried to do it,but all times I miss something in your code (No comments, no remarks).Could you,please, supply MenuExtender Right-To-Left.I think you will spend for it not more then 10 min.

My e-mail is: caesar_zav@hotmail.com

Thanks in advance,

Caesar Zavaluev
GeneralNever Mind
smokingbrat
13:07 29 Dec '05  
I found the issue. http://support.microsoft.com/?id=827043[^]

smokingBrat
GeneralRe: Never Mind
Marcelo Miorelli
1:02 18 Sep '06  
Dear smokingbrat, dear all,

The menuextender is very good.
I was struggling to develop one myself, and found all the answers but one here.

The issue I had not found, it is pointed out by smokingbrat:


BUG: The ContextMenu control that is associated with the NotifyIcon component is not displayed when you set the OwnerDraw property of menu items in the ContextMenu control to true


I still would like to have this done but dont know if it would be possible.

Microsoft has confirmed that this is a bug in the microsoft products.

Regards
Marcelo Miorelli


Hare Krishna

QuestionQuestion
smokingbrat
11:35 29 Dec '05  
Nice Work!

Does this work for notifyIcon(systray)? I created a context menu for notifyIcon but when I run the app, the context menu was blank (no text, no icon..). The event handlers for click event of the contextmenuitems were working though Confused .

Thanks



smokingBrat
GeneralFONT IN APPLICATION
datvpsc77
16:11 6 Dec '05  
HI all!Smile
I am developing a application that it's font(menu font,message box font,label,text...) is displayed independent on windows font setting.
I am using C++ .NET 2003(.NET ver 1.1) to develop it.

Can you help me !!
How to set my application font independent on windows system font setting?

Thanks for all!

Hoang Quoc Dat
it-division of VPSC company
75 Dinh Tien Hoang - Ha Noi - Viet Nam
email: datvpsc@yahoo.com

dat
GeneralProblems when using it with combobox
ExXon
5:38 31 Oct '05  
I've tried this using multiple menuItems, which all works great. But if I assign a context menu (using the MenuItem Extender) to a combobox, strange things starts to happen...

The menue choices will not show, neither text nor pictures. Probably just something I'm doing wrong here, so if anyone has the procedure to use this with a combobox, I would be very grateful!

Yours,
Daniel

Daniel
GeneralExcellent !
kim.hauser
5:50 25 Oct '05  
Thanx for this worderfull extention - and all the comments - for me this control works great. thanx again - kim

(why isn't .net more like java 8)

GeneralNot only MDI
Alexey A. Popov
2:22 20 Oct '05  
I say an excellent article and an excellent code, but:
I've found one serious limitation - this class cannot be used in a MDI application. The reason lies out of my class - it's a common problem for the framework. You can easily ascertain that your owner drawn menu items in a MainMenu of a MDI parent form can disappear. This limitation applies not only to MDI applocation but ot any application/form that uses menu merge system. I found it while writing a small MVC-based application - when changing views I needed to change the main form menu. Because those views and their menu commands were not known at compile time (there was a some plugin system), I used MergeMenu method. I also used an extender provider similar to yours and I've had a whole lot of a trouble figuring out why my nice icons got disappeared and my application crashed badly.
The problem is that a component and it's extender are too loosely coupled by nothing but IDE and as soon as you start to change things generated by IDE you are in trouble.
At the end I found that you should use CloneMenu method before merging and started to draw the icons in a main from event handler completely avoiding the menu extender. What a pity.
GeneralRe: Not only MDI
datvpsc77
17:41 6 Dec '05  
Can you send me a sample how to using CloneMenu to resolve this problem?

Thanks!

Hoang Quoc Dat
IT-DIVISION VPSC COMPANY
75 Dinh tien hoang - Ha Noi - Viet Nam
email: datvpsc@yahoo.com



công hoa xa hoi chu nghia viet nam
GeneralRe: Not only MDI
Alexey A. Popov
20:32 8 Dec '05  
The code is taken verbatim from a working project (not the best snippet though):
private void MergeMenu(MainMenu otherMenu)
{
if(null == otherMenu)
{
MainMenu oldMainMenu = Menu;
MainMenu mainMenu2 = mainMenu.CloneMenu();
Menu = mainMenu2;
if(null != oldMainMenu)
oldMainMenu.Dispose();
}
else {
MainMenu oldMainMenu = Menu;
MainMenu mainMenu2 = mainMenu.CloneMenu();
MainMenu otherMenu2 = otherMenu.CloneMenu();
mainMenu2.MergeMenu(otherMenu2);
Menu = mainMenu2;
oldMainMenu.Dispose();
otherMenu2.Dispose();
}
}
Here Menu is the Form.Menu property, mainMenu is the field of the current form and the othermenu is anoter menu to be merged with the main menu; can be null. Basically this method merges the main menu with another menu and sets the result as the main menu or resets the main menu back to the default one.
There are obvious things to improve, mainly guard the code from menu handles leak by putting all calls to Dispose() methods to a finally statement.
GeneralRe: Not only MDI
datvpsc77
18:22 12 Dec '05  
Thanks for your attention!
But I do not known where your code has placed.What event
is used here?

Can you help me to resolve this problem?

I uses C++ .NET 2003 to develop my application. I use
MenuExtender in my application but after a child form appears, the main menu hides.

Can you show me more detail about your code(in any .NET languages)

Thanks for your support!
HOANG QUOC DAT
IT - DIVISION
VPSC COMPANY
75 DINH TIEN HOANG - HA NOI - VIET NAM
EMAIL: datvpsc@yahoo.com


DAT
GeneralRe: Not only MDI
datvpsc77
23:28 14 Dec '05  
OK! I have just found the way to resolve this problem.
Many Thanks for your support.
Smile
HOANG QUOC DAT
IT-DEPARTMENT OF VPSC COMPANY
75 DINH TIEN HOANG - HANOI - VIETNAM


DAT
GeneralMenuItem Mouseover
Jacques Crocker
12:53 24 May '05  
Hi. Is it possible to capture a menuItem mouseover event?
GeneralHow can I add a "name" as property ???
AgnesCheng
18:45 27 Mar '05  
I only know vb.net Does there is vb.net version ??
I try to modify the code (in C#) to create a new property"myName"
But I am totally fail and no idea.
Can you help me ??
Thanks in advance.Roll eyes

Agnes
GeneralI'm getting an error "Does not have a strong name"
dakrin
14:31 17 Mar '05  
Im probably just doing something stupid. I googled and the solution i found was to place the .dll in the debug folder, but it hasn't worked.
GeneralRe: I'm getting an error "Does not have a strong name"
dakrin
8:56 18 Mar '05  
Figured it out. Project had an snk defined, so i had to edit it so it didn't use a strong named key.
GeneralmenuItem.Checked Doesn't work
id10t
8:23 20 Feb '05  
Why can't I compair against this?
menuItem.Checked?
It will only return true values.

Thanks


Last Updated 1 Mar 2004 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010