Introduction to Windows Forms

Replacing, Cloning & Merging

A common practice in Windows applications is to change menus according to the data displayed in the client window. To save you from having to create and destroy menus on-the-fly, .NET allows you to swap out menus and create new ones by merging one or more predefined menu hierarchies.

Listing 3.1.10 shows a simple application that constructs several menus and then combines them in different ways according to selections made by the user.

Listing 3.1.10 menuswop.cs: Manipulating, Cloning, and Merging Menus

 using System;
 using System.Drawing;
 using System.ComponentModel;
 using System.WinForms;

 namespace Sams {

 class menuswop : System.WinForms.Form
 {
   MainMenu m_menu;
   MenuItem m_editmenu,m_menumenu,m_switchitem,m_showsecond,m_merge;
   MenuItem m_playmenu;
 
   bool m_bswop;
   bool m_bshowsecond;
   bool m_bmerge;
 
   // private helper function for the BuildMenu function.
   void addmenuitem(MenuItem menu, string s)
    {
      MenuItem temp=new MenuItem(s);
      temp.Enabled= false;
      menu.MenuItems.Add(temp);
    }
 
    // This builds a menu structure from copies
    // of the originals using CloneMenu.
    void BuildMenu()
    {
      m_menu=new MainMenu();
      m_menu.MenuItems.Add(m_menumenu.CloneMenu());
 
      if(m_bmerge) // when we merge...
      {
        MenuItem temp=new MenuItem();
 
        if(!m_bswop)
        {
          addmenuitem(temp,"Edit");
          temp.MergeMenu(m_editmenu.CloneMenu());
        }
        else
        {
          addmenuitem(temp,"Play");
          temp.MergeMenu(m_playmenu.CloneMenu());
        }
 
        temp.MenuItems.Add(new MenuItem("-"));
 
        if(m_bshowsecond)
        {
          if(!m_bswop)
          {
            addmenuitem(temp,"Play");
            temp.MergeMenu(m_playmenu.CloneMenu());
          }
          else
          {
            addmenuitem(temp,"Edit");
            temp.MergeMenu(m_editmenu.CloneMenu());
          }
        }
 
        temp.Text = "&Merged";
        m_menu.MenuItems.Add(temp);
 
      }
      else // when we dont merge...
      {
        if(!m_bswop)
        {
          if(m_bshowsecond)
          {
            m_menu.MenuItems.Add(m_editmenu.CloneMenu());
          }
          m_menu.MenuItems.Add(m_playmenu.CloneMenu());
        }
        else
        {
          if(m_bshowsecond)
          {
            m_menu.MenuItems.Add(m_playmenu.CloneMenu());
          }
          m_menu.MenuItems.Add(m_editmenu.CloneMenu());
        }
      }
 
      this.Menu = m_menu;
    }
 
    //This method sets or resets the checks on menu items
    //note how the MenuItem collection is accessible as an array.
    void PopupMenuMenu(Object sender, EventArgs e)
    {
      m_menu.MenuItems[0].MenuItems[0].Checked = m_bswop;
      m_menu.MenuItems[0].MenuItems[1].Checked = m_bshowsecond;
      m_menu.MenuItems[0].MenuItems[2].Checked = m_bmerge;
    }
 
   // The event handler for the switch menu entry
   void OnSwitchMenu(Object sender, EventArgs e)
   {
     m_bswop = !m_bswop;
     BuildMenu();
   }

   //The event handler for the show menu entry
   void Onshowsecond(Object sender, EventArgs e)
   {
     m_bshowsecond = !m_bshowsecond;
     BuildMenu();
   }

   //The event handler for the merge menu entry
   void OnMerge(Object sender, EventArgs e)
   {
     m_bmerge = !m_bmerge;
     BuildMenu();
   }

   public menuswop()
   {
     // setup a main menu
     m_menumenu = new MenuItem("&Menu");
     m_menumenu.Popup += new EventHandler(PopupMenuMenu);

     //Create the switch item.
     m_switchitem=new MenuItem("&Switch");
     m_switchitem.Click+=new EventHandler(OnSwitchMenu);
     m_menumenu.MenuItems.Add(m_switchitem);

     m_showsecond = new MenuItem("&Show");
     m_showsecond.Click+= new EventHandler(Onshowsecond);
     m_menumenu.MenuItems.Add(m_showsecond);

     m_merge = new MenuItem("&Merge");
     m_merge.Click += new EventHandler(OnMerge);
     m_menumenu.MenuItems.Add(m_merge);

     // create a second menu
     m_editmenu=new MenuItem("&Edit");
     m_editmenu.MenuItems.Add(new MenuItem("Cut"));
     m_editmenu.MenuItems.Add(new MenuItem("Copy"));
     m_editmenu.MenuItems.Add(new MenuItem("Paste"));

     // and an alternative.
     m_playmenu=new MenuItem("&Play");
     m_playmenu.MenuItems.Add(new MenuItem("Normal"));
     m_playmenu.MenuItems.Add(new MenuItem("Fast Forward"));
     m_playmenu.MenuItems.Add(new MenuItem("Reverse"));

     m_bshowsecond=true;

     //Now build the menu from its parts.
     BuildMenu();

   }

   public static void Main()
   {
     Application.Run(new menuswop());
   }
 }


 }// end of Sams namespace

In this listing you can see that initially the menu creation process is normal, but that no menus are actually added to the MenuItem lists of a parent. The Edit and Play menus are kept separate.

The BuildMenu function on line 28 creates a new main menu and assigns it to the application's main menu. This will cause the GC to delete all of the submenus and entries from the main menu. BuildMenu then goes on to create the menu order or merge the two submenus into one, depending on the settings of the class member variables.

This technique allows you to create an initial set of menu items with all their handlers and settings in place, and then use them in many combinations without having to keep track of them or reset them to default values.

In Listing 3.1.10 the merge is very simple. There are however, more complex ways that MenuItems can be combined. The MenuItem has a merge order property so that when they are merged into another menu, they will sort themselves into a specific sequence. For example, you might want to have a File menu on which functionality is grouped according to the file type or system resources. With the menu merge order, you can ensure that common functions are first in the menu and less common ones are last. To illustrate the merge order functionality, Listing 3.1.11 shows a program in which the menu sorts itself according to the popularity of the selections.

Listing 3.1.11 menuorder.cs: On-the-Fly Menu Reordering and Merging

 using System;
 using System.Drawing;
 using System.ComponentModel;
 using System.WinForms;

 namespace Sams {
 class menuorder : System.WinForms.Form
 {
   MainMenu m_menu;
   MenuItem m_workingmenu;
   MenuItem m_menuentry;

   // this event handler is called whenever an item is used
   void OnUsed(Object sender, EventArgs e)
   {
     for(int i=0;i<m_menuentry.MenuItems.Count;i++)
       m_menuentry.MenuItems[i].MergeOrder ++;

     MenuItem m=(MenuItem)sender;

     m.MergeOrder--;

     if(m.MergeOrder < 0)
       m.MergeOrder = 0;

   }

   // this event handler is also invoked. You could have
   // many event handlers attached to the Click sources
   void OnClicked(Object sender, EventArgs e)
   {
     MenuItem m=(MenuItem)sender;
     MessageBox.Show("You clicked "+m.Text);
   }

   //As a menu is popped up it is constructed on the fly.
   void OnPopup(Object sender, EventArgs e)
   {
     m_menu.MenuItems.Clear();
     m_workingmenu.MenuItems.Clear();
     m_workingmenu.MergeMenu(m_menuentry);
     m_menu.MenuItems.Add(m_workingmenu);
   }

   // Sets up the initial menu text and orders.
   public menuorder()
   {

     string[] s=new string[8]{"Cats","Dogs","Elephants","Geese",
"Mooses","Rats","Giunea-pigs","Horses"};

     m_menu = new MainMenu();
     m_menuentry = new MenuItem("&Menu");
     m_menuentry.Popup += new EventHandler(OnPopup);

     m_workingmenu = new MenuItem();

     for(int i=0;i<8;i++)
     {
       MenuItem temp = new MenuItem(s[i]);
       temp.MergeOrder=i;
       temp.Click+=new EventHandler(OnUsed);
       temp.Click+=new EventHandler(OnClicked);
       m_menuentry.MenuItems.Add(temp);
     }

     m_workingmenu.MergeMenu(m_menuentry);
     m_menu.MenuItems.Add(m_workingmenu);
     this.Menu = m_menu;
   }

   // instantiates and runs the application.
   public static void Main()
   {
     Application.Run(new menuorder());
   }
 }

 }

This listing also illustrates how you can add more than one event handler to a Windows Forms Click. The same is true for the Select, Popup, and all other events.

You might also like...

Comments

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“A computer is a stupid machine with the ability to do incredibly smart things, while computer programmers are smart people with the ability to do incredibly stupid things. They are, in short, a perfect match” - Bill Bryson