Universal menu command handle pattern

Universal menu command handle pattern
summary
(This article is translate version , original version written in chinese , you can see it at http://www.cnblogs.com/xdesigner/archive/2006/10/07/522927.html )
  Some WinForm application has a lot of menuitem , standard menum item in .NET framework is not perfect , so result in a lots of MenuItem_Click function , it is not easy to maintains those code , this article discuss a pattern which handle menu command universal .
  I think some people complain that a part of the standard WinForm library in .NET Framework 1.1 is poor , some body fleer that Microsoft employ hight middle school students to write System.Windows.Forms , of cause , this viewpoint is inflation . but in the author's experience , I find that a part of the standard WinForm library is really poor .
  Microsoft has thousands of good software engineer , according to it's power , it can provide a powerful , perfect standard WinForm library . Here , I guess microsoft publish a library with some disadvantage wilful . this is nothing but a business policy . Microsoft drop a blank and fetch the third party to exert . This  can maintenance the microsoft's empire. I think it is a good idea .
  Now talk about the content . In Winform application , you use a lot of menu , int VS.NET IDE , it provide a menu designer to design applicatin's menu structure , when you put a MainMenu or ContextMenu into a form , you can use menu designer to build menu item(type is System.Windows.Forms.MenuItem ) in a tree structure . and aim at every menuItem , you can write  code to handle it's Click event .
   This is fit to a small application , but not fit a big , complicated application with a lot of MenuItem , in a big applicatin , there are a lot of MenuItem_Click function , a WinForm application in a good design , it's logic collect together and call then use a single interface instead of distributed in lot's of MenuItem_Click or Button_Click functions . In this way , the MenuItem_Click function only call a single interface .
   For example , a from define a golbal logic function interface , define as "void HandleCommand( string Command )" , in this function there are a big switch structure , this function execute logic action bases parameter "Command" . Then in this form , there are some code like following
void MenuItem_Open_Click( object Sender , System.EventArgs e  )
{
    HandleCommand( "Open" );
}
void MenuItem_Save_Click( object Sender , System.EventArgs e  )
{
    HandleCommand( "Save" );
}
  There are a lot's of this kind of code is not a good smell , itt can be reform ,  you can let all MenuItem ' s Click event handler point to a same function , this function can write in

void MenuItem_Click( object Sender , System.EventArgs e )
{
    if( Sender == MenuItem_Open )
        HandleCommand( "Open" );
    else if( Sender == MenuItem_Save )
        HandleCommand( "Save" );
    else if ..........
}
  But this structure is not perfection , because people who write or maintain this  function must know every MenuItem's name , this is do harm to maintain code , If a MenuItem's function changed , you must change this MenuItem's name and modify MenuItem_Click's code .
  At there , How we hope than MenuItem type has Command property , if MenuItem has  property Command , then the universal menum click handler can write like

void MenuItem_Click( object Sender , System.EventArgs e )
{
    HandleCommand( ( ( MenuItem ) Sender ).Command );
}

  Very simple , easy to maintains , all you do is manage every MenuItem's Command property .
  But MenuItem has not Command property , so some people expend MenuItem type , build his owner MenuItem type , append Command property , then can use the universal MenuItem_Click function .
  At there , I did not create my owner MenuItem type , stand two point , first , IDE's MenuItem designer does not support Custom MenuItem type . Secend , there are  a lot of old application already use standard MenuItem type , Convert then to use Custom MenuItem type , it is a gread work.

   So I bring out a universal MenuItem command handler model , the primary code no more than 100 , it can support single handle menu command event without custom MenuItem type , this code is following


 

    public delegate void MenuCommandHandler( System.Windows.Forms.MenuItem MenuItem , string Command );

    public class MenuCommandSender
    {
        public MenuCommandSender()
        {
            myHandler = new EventHandler( this.MenuClick );
        }
        public event MenuCommandHandler MenuCommand = null;
        public void Clear()
        {
            foreach( BindItem item in myItems )
            {
                if( item.MenuItem != null )
                {
                    item.MenuItem.Click -= myHandler ;
                }
            }
            myItems.Clear();
        }
        public int Count
        {
            get{ return myItems.Count ;}
        }
        public void Registe( string strCommand , System.Windows.Forms.MenuItem MenuItem )
        {
            BindItem item = new BindItem();
            item.Command = strCommand ;
            item.MenuItem = MenuItem ;
            MenuItem.Click += myHandler ;

            myItems.Add( item );
        }
        public string GetCommand( System.Windows.Forms.MenuItem MenuItem )
        {
            foreach( BindItem item in myItems )
            {
                if( item.MenuItem == MenuItem )
                    return item.Command ;
            }
            return null;
        }
        public System.Windows.Forms.MenuItem GetMenuItem( string strCommand )
        {
            foreach( BindItem item in myItems )
            {
                if( item.Command == strCommand )
                    return item.MenuItem ;
            }
            return null;
        }

        private System.Collections.ArrayList myItems = new System.Collections.ArrayList();
        private class BindItem
        {
            public System.Windows.Forms.MenuItem MenuItem = null;
            public string Command = null;
        }
        private System.EventHandler myHandler = null;
        private void MenuClick( object sender , System.EventArgs e )
        {
            if( MenuCommand != null )
            {
                foreach( BindItem item in myItems )
                {
                    if( item.MenuItem == sender )
                    {
                        MenuCommand( item.MenuItem , item.Command );
                        break;
                    }
                }
            }
        }
    }//public class MenuCommandSender

   In your application , you create a MenuCommandSender instance , define a function as following and bind it to MenuCommandSender's MenuCommand event .

void HandleMenuCommand( MenuItem item , string Command )
{
    HandleCommand( Command );
}
  
  then use MenuCommandSender's Registe member function to registe menu command , for example

MenuCommandSender  cmd = new MenuCommandSender();
cmd.MenuCommand += new MenuCommandHandler( HandleMenuCommand );
cmd.Registe( "Open" , MenuItem_Open );
cmd.Registe( "Save" , MenuItem_Save );

  then , this pattern start . The work for convert old application use this model is  acceptable .
  In fact , this pattern can expend to handle System.Windows.Forms.Button or other WinForm control , not only System.Windows.Forms.MenuItem .
  This pattern is very simple and useful , I hope it is benefic to some developer who handle a lot of MenuItems .
XDesigner Studio ( http://www.xdesigner.cn/default-eng.htm ) 2006-10-9

posted on 2006-10-10 09:26  袁永福 电子病历,医疗信息化  阅读(731)  评论(2编辑  收藏  举报

导航