Introduction
This article shows how to create menus dynamically in C#, in a few easy steps. It also shows how to use the OwnerDraw
feature of MenuItem
(s).
Background
Some months back, seeing some of my articles, someone sent me an E-mail message asking for help on creating menu items to display Most Recent Used files to a project. This request was for a solution in VC++. Since I was quite familiar with it, I sent him the necessary source, but recently when I switched to C# (temporarily), I came across the same problem and could not find any reference to creating such menus in the MSDN Help. I did find some sketchy info in this regard, I worked on the bits of info and found that it is not very difficult, and not very easy either. But however when I tried this same technique in Visual Basic side of .NET, I did not succeed (I am at this point of time still trying).
Important
This project was developed in .NET (7.0 - first version of Visual Studio .NET) and the project uses the following registry key to retrieve and display the most recent project, in the menu.
RegistryKey regKey =
Registry.CurrentUser.OpenSubKey
("Software\\Microsoft\\VisualStudio\\7.0\\ProjectMRUList");
If you are using a later version of Visual Studio .NET, you may have to modify the above line to reflect your version of .NET; maybe something like this, and re-build the application.
RegistryKey regKey =
Registry.CurrentUser.OpenSubKey
("Software\\Microsoft\\VisualStudio\\7.1\\ProjectMRUList");
Using the code
I have not spent time trying to develop a separate class for this purpose, since the technique is quite simple, and personally I would encourage developers to stick to a method of "Copy / Paste / Modify". Thus you learn more then adding classes made by others, wherein you create menus by passing a few parameters, and learn nothing in the bargain. You are also forced to add the copyright notice of the author.
Since the project is very small I have included some of the important parts of the source in this article.
public void UpdateMenu()
{
RegistryKey regKey = Registry.CurrentUser.OpenSubKey
("Software\\Microsoft\\VisualStudio\\7.0\\ProjectMRUList");
if (regKey == null)
{
return;
}
MenuItem mnu = new MenuItem();
String[] filename = regKey.GetValueNames();
IEnumerator iEnum = filename.GetEnumerator();
while(iEnum.MoveNext())
{
String val = (String)iEnum.Current;
String data = (String)regKey.GetValue(val);
MenuItem mi = AddMenuItem(data);
mnu.MenuItems.Add(mi);
}
menuItemRecentProjects.MergeMenu(mnu);
regKey.Close();
}
Function to add each MenuItem
is as below:
private MenuItem AddMenuItem(String title)
{
MenuItem mi = new MenuItem(title);
mi.Click += new
System.EventHandler(this.menuItemDynamicMenu_Click);
mi.OwnerDraw = true;
mi.DrawItem += new
System.Windows.Forms.DrawItemEventHandler
(this.menuItemDynamicMenu_DrawItem );
mi.MeasureItem += new
System.Windows.Forms.MeasureItemEventHandler
(this.menuItemDynamicMenu_MeasureItem);
return mi;
}
Code for ..._MeasureItem(...)
and ..._DrawItem(...)
is shown below. Note, since the MenuItem
s are created dynamically at run-time, the following events cannot be created from the Properties/Events window of the Visual Studio IDE, but rather have to be created manually. I have named the events menuItemDynamicMenu_MeasureItem
and menuItemDynamicMenu_DrawItem
. You can possibly name them anything you prefer, but it is better to append _MeasureItem
and _DrawItem
to recognize it easily. Parameters for each of these events must be as below. If you leave out the _MeasureItem
event your menu will be 10x2 in size.
..._MeasureItem(object sender, System.Windows.Forms.MeasureItemEventArgs e)
..._DrawItem(object sender,
private void menuItemDynamicMenu_MeasureItem(object sender,
System.Windows.Forms.MeasureItemEventArgs e)
{
MenuItem item = (MenuItem)sender;
e.ItemHeight = 20;
SizeF stringSize = new SizeF();
stringSize = e.Graphics.MeasureString(item.Text, this.Font);
e.ItemWidth = (int)stringSize.Width;
}
Code for _DrawItem(...)
.
private void menuItemDynamicMenu_DrawItem(object sender,
System.Windows.Forms.DrawItemEventArgs e)
{
SolidBrush brush;
if(e.State.Equals(DrawItemState.Selected |
DrawItemState.NoAccelerator ))
{
Pen blackPen = new Pen(Color.Black, 1);
e.Graphics.DrawRectangle(blackPen, e.Bounds);
brush = new SolidBrush(Color.FromArgb(40, 10, 10, 255));
e.Graphics.FillRectangle(brush, e.Bounds);
return;
}
if(e.State.Equals(DrawItemState.NoAccelerator))
{
Pen whitePen = new Pen(Color.White, 1);
e.Graphics.DrawRectangle(whitePen, e.Bounds) ;
SolidBrush brushErase = new SolidBrush(Color.White );
e.Graphics.FillRectangle(brushErase, e.Bounds);
MenuItem item = (MenuItem)sender;
Rectangle rect = e.Bounds;
SolidBrush drawBrush = new SolidBrush(Color.Black);
RectangleF drawRect = new RectangleF( e.Bounds.X+20,
e.Bounds .Y, e.Bounds.Width , e.Bounds .Height);
brush = new SolidBrush(Color.FromArgb(236, 233,216));
e.Graphics.FillRectangle(brush,
rect.Left, rect.Top, 18, rect.Bottom);
e.Graphics.DrawString(item.Text , e.Font,
drawBrush, drawRect );
imageList1.Draw(e.Graphics, rect.Left+1, rect.Top ,14,14, 0);
}
}
History