Figure 1: Colorized options
Figure 2: Enabled options
Introduction
Some time ago I was writing a Corporate System with lots of menu options, so it was not easy to visually keep track of implemented and pending options. As a former Visual C++ developer, I miss the MFC's main menu implementation, where non-implemented options appear disabled automatically.
I have not reproduced the exactly MFC functionality, but extended the idea to color signalling, as shown in figures above. This provides my customer a clear idea of work progress. Optionally, the tool tips will show the associated method name for each menu option.
Using the Code
For using the MenuDecorator class, you must follow two simple steps:
- Add MenuDecorator.cs class file to your project.
- Inside your code (maybe main form's constructor), call the
ColorizeImplementedOptions() or EnableImplementedOptions() static method, passing a reference to your MenuStrip object.
The first method needs to be invoked passing two colors also for implemented and non-implemented options, as shown below, plus a boolean value to show methods' name in tooltips:
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
MenuDecorator.ColorizeImplementedOptions
(this.MainMenu, Color.Blue, Color.Red, true);
This will produce a result similar to Figure 1.
The second static method, will not change option's colors, but will enable implemented options and disable others. Also you can specify to show the tool tips with associated method names. Here is an example of use:
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
MenuDecorator.EnableImplementedOptions(this.MainMenu, true);
The result will be similar to Figure 2.
Points of Interest
The core section of this little static class is a complex sequence of reflection methods to establish if a specific menu option has some Click event attached to it. It is called recursively, traversing all menu trees. Here is the code portion where Click event is evaluated for enabling or disabling:
public class MenuDecorator
{
private const BindingFlags Flags = BindingFlags.Static | BindingFlags.Instance |
BindingFlags.NonPublic | BindingFlags.FlattenHierarchy;
private static FieldInfo ClickInfo =
typeof(ToolStripMenuItem).GetField("EventClick", Flags);
private static void EnableMenuItem(ToolStripMenuItem _item)
{
PropertyInfo events = _item.GetType().GetProperty("Events", Flags);
if (_item.HasDropDownItems)
{
_item.Enabled = true; foreach (ToolStripItem dropitem in _item.DropDownItems)
{
if (dropitem.GetType() == typeof(ToolStripMenuItem))
EnableMenuItem((ToolStripMenuItem)dropitem);
}
}
else
{
EventHandlerList handlers =
(EventHandlerList)events.GetValue(_item, null);
Delegate d = handlers[ClickInfo.GetValue(_item)];
if (_showTips)
_item.ToolTipText = d == null ? "[empty]" : d.Method.Name;
_item.Enabled = !object.Equals(d, null);
}
}
The solution file included with this article, has been produced with Visual Studio 2008, so you won't be able to load directly from Visual Studio 2005, but you can create a new solution and attach the project file manually.
History
- 4th June, 2007 - First version
- 29th November, 2007 - Added tooltip feature
- 27th June, 2008 - General revision