Click here to Skip to main content
15,888,177 members
Articles / Programming Languages / C#
Article

C# Creating Dynamic Menus

Rate me:
Please Sign up or sign in to vote.
3.38/5 (14 votes)
5 Sep 20032 min read 109.7K   3.9K   74   2
Creating Menus Dymanically in C#.

Sample Image - DynamicMenus.jpg

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.

C#
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.

C#
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.

C#
public void UpdateMenu()
{

// retreive names of all recent project
// from the system registry
   RegistryKey regKey = Registry.CurrentUser.OpenSubKey
       ("Software\\Microsoft\\VisualStudio\\7.0\\ProjectMRUList");
   if (regKey == null)
   {
       // such key does not exist
       return;
   }

   MenuItem mnu = new MenuItem();                
   String[] filename = regKey.GetValueNames(); 
   IEnumerator iEnum = filename.GetEnumerator();

   // Iterate through all items
   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:

C#
private MenuItem AddMenuItem(String title)
{
   // create a new menuitem
   MenuItem mi = new MenuItem(title);
   // set as Delegate for the Click Event of this MenuItem
   mi.Click +=  new 
     System.EventHandler(this.menuItemDynamicMenu_Click);

   // Ownerdraw is needed only if you want to
   // add Icons and custom highlighting etc
   mi.OwnerDraw = true;
   // ..._MeasureItem, ..._DrawItem Virtual function are called
   // by the system to render the items individually
   // every time a visual aspect changes
   mi.DrawItem +=  new 
     System.Windows.Forms.DrawItemEventHandler
     (this.menuItemDynamicMenu_DrawItem ); 
   mi.MeasureItem += new 
     System.Windows.Forms.MeasureItemEventHandler
     (this.menuItemDynamicMenu_MeasureItem);
   // ..._DrawItem and ..._MeasureItem EventHandler Delegates 
   // for each MenuItem are created above
   return mi;
}

Code for ..._MeasureItem(...) and ..._DrawItem(...) is shown below. Note, since the MenuItems 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.

C#
..._MeasureItem(object sender, System.Windows.Forms.MeasureItemEventArgs e)
..._DrawItem(object sender, 
C#
private void menuItemDynamicMenu_MeasureItem(object sender, 
       System.Windows.Forms.MeasureItemEventArgs e)
{
   // retreive the MenuItem in question
   // note : ..._MeasureItem is called before ..._DrawItem
   MenuItem item = (MenuItem)sender;
   // we set the height of each item to 20
   // remember the icons are 16x16
   e.ItemHeight = 20;
   SizeF stringSize = new SizeF();
   stringSize = e.Graphics.MeasureString(item.Text, this.Font);
   // set the width of the item based on the 
   // length of the prompt
   e.ItemWidth = (int)stringSize.Width;
}

Code for _DrawItem(...).

private void menuItemDynamicMenu_DrawItem(object sender, 
             System.Windows.Forms.DrawItemEventArgs e)
{
   // unfortunately only 2 states are passed to this function
   // NoAccelerator
   // Selected, NoAccelerator

   SolidBrush brush;
   if(e.State.Equals(DrawItemState.Selected | 
                   DrawItemState.NoAccelerator ))
   {
      // Item is Selected highlight the Item
      Pen blackPen = new Pen(Color.Black, 1);
      e.Graphics.DrawRectangle(blackPen, e.Bounds); 
      brush = new SolidBrush(Color.FromArgb(40, 10, 10, 255));
      // create a highlight rectangle
      e.Graphics.FillRectangle(brush, e.Bounds); 
      return;
   }
            
   if(e.State.Equals(DrawItemState.NoAccelerator))
   {
      // Item is not selected, remove highlight rectangle
      // created above
      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;
            
      // get the MenuItem's Rectangle
      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));
      // draw a transparent rectangle over the Image
      // else the Image will not be visible
      e.Graphics.FillRectangle(brush, 
            rect.Left, rect.Top, 18, rect.Bottom);

      // Draw MenuItem Text , you can use some funcky 
      // Font for this purpose
      e.Graphics.DrawString(item.Text , e.Font, 
                            drawBrush, drawRect );

      // Render the Image (Icon)
      // i have used a ImageList 
      imageList1.Draw(e.Graphics, rect.Left+1, rect.Top ,14,14, 0);
   }
}

History

  • First version.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
India India
Nothing to boast about

Comments and Discussions

 
GeneralSlight problem Pin
mhuntley7-Nov-03 13:05
mhuntley7-Nov-03 13:05 
GeneralRe: Slight problem Pin
Barretto VN10-Mar-05 2:18
Barretto VN10-Mar-05 2:18 
Thanks, and sorry for the extremly long delay in replying, the reason being that i did not get this message by e-mail


Visit my Home Page for updates http://members.lycos.co.uk/barrettovn

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.