After seeing that there was only one thing left on my list and it wasn’t important I’ve decided to release BetterMenu tonight.
What is BetterMenu?
BetterMenu is a component you can add to a .NET application which adds images and custom drawing to menus based on the MainMenu and ContextMenu controls. Unlike regular custom drawing of menus this component handles MDI applications with menu merging and using the MDI List menu option. Also included is a component that is used by BetterMenu to make sense of the MdiChildActivate event.
Copyright (c) 2004-2006, James T. Johnson
ImageIndexEditor/Converter Copyright (c) 2004, Eugene Pankov
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The images used by the menu items in the Demo application are not covered by this license which is why they are not included as separate files.
A brief how-to follows the break.
How to use BetterMenu
First things first, you need to add the BetterMenu component to your toolbox. With a Windows Form open go to your toolbox and right click on the tab you wish to add the component to. Choose “Choose Items” or “Add/Remove Items” depending on what version of Visual Studio you are using. Choose the browse tab or click the browse button and select the MrDotNet.BetterMenu.dll assembly from the demo or the one you built from source.
The BetterMenu component works by using the IExtenderProvider interface provided by the .NET framework. This lets the component add psuedo-properties to other controls on the design surface. For more information about IExtenderProvider I have written an article about it on CodeProject.
The advantage this component has over similar ones is that you don’t have to do anything different to start taking advantage of the component. Once you drop it on the form the MenuItems on the form will have the properties you need to control the way the menu looks. Most of it should be easy to figure out, the Image property on the menu item will dictate the image that should be drawn next to the menu item. The ImageIndex property works with the ImageList properites on the BetterMenu component.
If you use the Image property or don’t assign Hot/Disabled image lists hot/disabled images will be created by the component.
The Description property controls the rich menu and textual separator behavior. If the menu is already a separator (that is the Text property is set to “-“) then setting the Description property will turn it into a textual separator. For other menu items the menu becomes a rich menu with a description beneath the main text of the item describing what it does. The EnableExtension property is a trick so that even if you don’t set any other properties the menu will still look like the others because of the custom drawing.
Speaking of drawing
If you want to customize the drawing process you can do that. First, create a new class inheriting from the abstract MrDotNet.BetterMenu.MenuDrawer. Then attach an event handler to the BetterMenu’s GetDrawer event and return an instance of your drawer. This should only be called once after the BetterMenu’s menu style is changed so you could keep state in the drawer. And since I’ve already hinted at it, the MenuStyle is a funky little property on the BetterMenu component.
While it appears to be an instance property, changing it to anything but Global will change a static property and all current instances of the BetterMenu will update themselves to the new menu style. Why the complexity? When you have an MDI application and use menu merging the BetterMenu component on the child form is still responsible for drawing the menu items. So if you change the style on the parent form but the child form doesn’t update, then you can have some menus drawn with a custom drawer and others drawn with the Office XP style.
I plan on writing a full article for CodeProject explaining the internals…then again I’ve said that for 2 years now 😀
Update: I forgot to include Eugene’s copyright on the source for the ImageIndexConverter and ImageIndexEditor I borrowed from his MenuItem Extender article