Fire my passion

Anything with my most passion……
利用IExtenderProvider扩展控件属性

以下是我学习IExtendProvider的心得,作为总结

 

1、首先要给类添加属性:

[ProvideProperty( "MenuImage", typeof(Component)) ]

用于提供给其他控件的属性名称

[DefaultProperty("ImageList")]

用于提供Extender的默认属性

2、要继承Component, IExtenderProvider两个类(接口)

                IExtenderProvider接口有一个方法要进行实现:

                CanExtend() : 指定此对象是否可以将其扩展程序属性提供给指定的对象

                另外还需要添加两个其他的公用方法

                SetPropertyName():为每个实例设置属性值

                GetPropertyName():得到控件实例的属性值

3、需要定义一个HashTable,用于存储控件的属性值。其中键存放的是控件的名称, 值存放的是控件的属性值.

4、在SetPropertyName()方法中, 可以设置控件的事件

5、在构造函数中, 添加如下代码, 用于设计模式

                                public PropertyName(System.ComponentModel.IContainer container)

                                {

                                                container.Add(this);

                                }

 

好了, 以上是我自己对这个接口的理解, 下面我把学习用的代码贴出来以供参考

using System ;

using System.ComponentModel ;

using System.Collections ;

using System.Diagnostics ;

using System.Windows.Forms ;

using System.Drawing ;

using System.Drawing.Drawing2D ;

 

namespace cn.everx.MenuImageLib

{

                [ProvideProperty( "MenuImage", typeof(Component)) ]

                [DefaultProperty("ImageList")]

                [ToolboxBitmap(typeof(MenuImage),"cn.everx.MenuImageLib.OfficeMenus.bmp")] 

      //上面这个属性没有作用

                public class MenuImage : Component, IExtenderProvider

                {

                                #region Private Attributes

                               

                                const int IMAGE_BUFFER = 25 ;

                                const int SHORTCUT_RIGHTBUFFER = 10 ;

                                const int SHORTCUT_BUFFER = 25 ;

                                int IMAGE_WIDTH = SystemInformation.SmallIconSize.Width ;

                                int IMAGE_HEIGHT = SystemInformation.SmallIconSize.Height ;

                               

                                Hashtable _hashTable = new Hashtable( );

                                ImageList _imageList = null;

                               

                                #endregion

                               

                                #region Constructors

 

                                public MenuImage(System.ComponentModel.IContainer container)

                                {

                                                container.Add(this);

                                }

                               

                                public MenuImage()

                                {

                                }

 

                                #endregion

                               

                                #region Public Members

                                public void SetMenuImage( Component component, string indexValue )

                                {

                                                // check if the string value is null, or not numeric

                                                // automatically throws and error if not during the convert

                                                if (indexValue != null)

                                                                if ( indexValue.Length > 0 )

                                                                {

                                                                                uint imageIndex = Convert.ToUInt16( indexValue ) ;

                                                                }

                                               

                                                // store the menuitem and related index in the local hashtable

                                                if ( _hashTable.Contains( component ) != true)

                                                {

                                                                _hashTable.Add( component, indexValue ) ;

                                                                MenuItem menuItem = (MenuItem) component ;

                                                               

                                                                // set the menu to owner drawn

                                                   menuItem.OwnerDraw = true ;         //这句很重要,因为需要进行菜单的自定义重绘

 

                                                                // hook up the menu owner drawn events

                                                                menuItem.MeasureItem += new MeasureItemEventHandler( OnMeasureItem ) ;

                                                                menuItem.DrawItem  += new DrawItemEventHandler( OnDrawItem ) ;

                                                }

                                                else

                                                {

                                                                _hashTable [ component ] = indexValue ;

                                                }

                                }

 

                                public string GetMenuImage( Component component )

                                {

                                                if( _hashTable.Contains( component ))

                                                                return (string) _hashTable[ component ] ;

 

                                                return null;

                                }

 

                                public bool CanExtend( object component )

                                {

                                                // only support MenuItem objects that are not

                                                // top-level menus (default rendering for top-level

                                                // menus is fine - does not need extension

                                                if ( component is MenuItem )

                                                {

                                                                MenuItem menuItem = (MenuItem) component ;

                                                                return ! (  menuItem.Parent is MainMenu ) ;

                                                }

                                                return false ;

                                }

 

                                public ImageList ImageList

                                {

                                                get{ return _imageList ;  }

                                                set{ _imageList = value; }

                                }

                               

                                #endregion

 

                                #region 私有方法 / 帮助类 

                                private int GetMenuImageIndex( Object sender )

                                {

                                                string menuImageValue = this.GetMenuImage( sender as Component ) ;

 

                                                if ( _imageList != null)

                                                                if ( menuImageValue != null )

                                                                                if ( menuImageValue.Length >= 0 )

                                                                                {

                                                                                                int imageIndex = Convert.ToInt32( menuImageValue ) ;

                                                                                                if ( imageIndex >= 0 && imageIndex < _imageList.Images.Count )

                                                                                                                return imageIndex ;

                                                                                }

 

                                                return -1 ;

                                }

 

                                private void OnMeasureItem( Object sender, MeasureItemEventArgs e )    

                                {

                                                // retrieve the image list index from hash table

                                                MenuItem menuItem = (MenuItem) sender ;

                                                MenuHelper menuHelper = new MenuHelper( menuItem, e.Graphics, _imageList ) ;

 

                                                // calculate the menu height

                                                e.ItemHeight = menuHelper.CalcHeight() ;

                                                e.ItemWidth = menuHelper.CalcWidth() ;

                                }

                               

                                private void OnDrawItem( Object sender, DrawItemEventArgs e )

                                {

                                                // derive the MenuItem object, and create the MenuHelper

                                                MenuItem menuItem = (MenuItem) sender ;

                                                MenuHelper menuHelper = new MenuHelper( menuItem, e.Graphics, _imageList ) ;

                                               

                                                // draw the menu background

                                                bool menuSelected = (e.State & DrawItemState.Selected) > 0 ;

                                                menuHelper.DrawBackground( e.Bounds, menuSelected ) ;

 

                                                if ( menuHelper.IsSeperator() == true )

                                                                menuHelper.DrawSeperator( e.Bounds ) ;

                                                else

                                                {

                                                                int imageIndex = this.GetMenuImageIndex( sender ) ;

                                                                menuHelper.DrawMenu( e.Bounds, menuSelected, imageIndex ) ;

                                                }

                                }

                               

                                #endregion

                               

                                #region MenuHelper Class

                               

                                private class MenuHelper

                                {

                                               

                                                #region Private Attributes

                                               

                                                // some pre-defined buffer values for putting space between

                                                // icon, menutext, seperator text, and submenu arrow indicators

                                                private const int SEPERATOR_HEIGHT = 8 ;

                                                private const int SBORDER_WIDTH = 1 ;

                                                private const int BORDER_SIZE = SBORDER_WIDTH * 2 ;

                                                private const int SBUFFER_WIDTH = 5 ;

                                                private const int LBUFFER_WIDTH = 15 ;

                                                private const int SHORTCUT_BUFFER_SIZE = 20 ;

                                                private const int ARROW_WIDTH = 15 ;

                                                private int IMAGE_WIDTH = SystemInformation.SmallIconSize.Width ;

                                                private int IMAGE_HEIGHT = SystemInformation.SmallIconSize.Height ;

                                                private int IMAGE_BUFFER_SIZE = SystemInformation.SmallIconSize.Width + 10 ;

                                               

                                                // holds the local instances of the MenuItem and Graphics

                                                // objects passed in through the Constructor

                                                MenuItem _menuItem = null ;

                                                Graphics _graphics = null ;

                                                ImageList _imageList = null ;

                                               

                                                #endregion

                                               

                                                #region Constructors

                                               

                                                public MenuHelper( MenuItem menuItem, Graphics graphics, ImageList imageList )

                                                {

                                                                _menuItem = menuItem ;

                                                                _graphics = graphics ;

                                                                _imageList = imageList ;

                                                }

                                               

                                                #endregion

                                               

                                                #region Public Members

                                               

                                                public int CalcHeight()

                                                {

                                                                // if the menu is a seperator, then return a fixed height

                                                                // otherwise calculate the menu size based on the system font

                                                                // and smalliconsize calculations (with some added buffer values)

                                                                if ( _menuItem.Text == "-" )

                                                                                return SEPERATOR_HEIGHT ;

                                                                else

                                                                {

                                                                                // depending on which is longer, set the menu height to either

                                                                                // the icon, or the system menu font

                                                                                if ( SystemInformation.MenuFont.Height > SystemInformation.SmallIconSize.Height )

                                                                                                return SystemInformation.MenuFont.Height + BORDER_SIZE ;

                                                                                else

                                                                                                return SystemInformation.SmallIconSize.Height + BORDER_SIZE ;

                                                                }

                                                }

                                               

                                                public int CalcWidth()

                                                {

                                                                // prepare string formatting used for rendering menu caption

                                                                StringFormat sf = new StringFormat() ;

                                                                sf.HotkeyPrefix = System.Drawing.Text.HotkeyPrefix.Show ;

                                               

                                                                // set the menu width by measuring the string, icon and buffer spaces

                                                                int menuWidth = (int) _graphics.MeasureString( _menuItem.Text, SystemInformation.MenuFont, 1000, sf).Width ;

                                                                int shortcutWidth = (int) _graphics.MeasureString( this.ShortcutText, SystemInformation.MenuFont, 1000, sf).Width ;

                                               

                                                                // if a top-level menu, no image support

                                                                if ( this.IsTopLevel() == true )

                                                                                return menuWidth ;

                                                                else

                                                                                return IMAGE_BUFFER_SIZE + menuWidth + SHORTCUT_BUFFER_SIZE + shortcutWidth ;

                                                }

                                               

                                                public bool HasShortcut()

                                                {

                                                                return ( _menuItem.ShowShortcut == true && _menuItem.Shortcut != Shortcut.None ) ;

                                                }

                                               

                                                /// <summary>

                                                /// Evaluates whether the <c>MenuItem</c> is a seperator by evaluating the text.

                                                /// </summary>

                                                /// <returns>Returns True/False whether the menu is a seperator.</returns>

                                                public bool IsSeperator()

                                                {

                                                                return ( _menuItem.Text == "-" ) ;

                                                }

                                               

                                                public bool IsTopLevel()

                                                {

                                                                return ( _menuItem.Parent is MainMenu ) ;

                                                }

                                               

                                                public string ShortcutText

                                                {

                                                                get

                                                                {

                                                                                if ( _menuItem.ShowShortcut == true && _menuItem.Shortcut != Shortcut.None )

                                                                                {

                                                                                                Keys keys = (Keys) _menuItem.Shortcut ;

                                                                                                return Convert.ToChar(Keys.Tab) + System.ComponentModel.TypeDescriptor.GetConverter(keys.GetType()).ConvertToString(keys) ;

                                                                                }

                                                                                return null ;

                                                                }

                                                }

 

                                                public void DrawMenu ( Rectangle bounds, bool selected, int indexValue )

                                                {

                                                                // draw the menu text

                                                                DrawMenuText( bounds, selected ) ;

                                                               

                                                                // since icons make the menu height longer,

                                                                // paint a custom arrow if the menu is a parent

                                                                // to augment the one painted by the control

                                                                // HACK: The default arrow shows up even for ownerdrawn controls ???

                                                                if ( _menuItem.IsParent == true )

                                                                {

                                                                                Image menuImage = null ;

                                                                                System.IO.Stream stream = this.GetType().Assembly.GetManifestResourceStream("cn.everx.MenuImageLib.SubItem16.ico") ;

                                                                                menuImage = Image.FromStream(stream) ;

                                                                                this.DrawArrow( menuImage, bounds ) ;

                                                                }

                                                               

                                                                // if the menu item is checked, ignore any menuimage index

                                                                // and draw the checkbox, otherwise draw the custom image

                                                                if ( _menuItem.Checked )

                                                                                DrawCheckBox ( bounds ) ;

                                                                else

                                                                {

                                                                                // see if the menu item has an icon associated and draw image

                                                                                if ( indexValue > -1 )

                                                                                {

                                                                                                Image menuImage = null ;

                                                                                                menuImage = _imageList.Images[indexValue] ;                                                                                         

                                                                                                DrawImage( menuImage, bounds ) ;

                                                                                }

                                                                }

                                                }

                                               

                                                public void DrawBackground( Rectangle bounds, bool selected )

                                                {

                                                                if (selected)

                                                                {

                                                                                Brush b = new SolidBrush(Color.FromArgb(255, 238, 194));

                                                                                _graphics.FillRectangle(b, bounds);

                                                                                _graphics.DrawRectangle(new 
                                                                                pen (SystemColors.ActiveCaption,1),bounds.X,bounds.Y,bounds.Width-1,bounds.Height-1);

                                                                }

                                                                else

                                                                {

                                                                                _graphics.FillRectangle(new SolidBrush(Color.White),bounds);

                                                                                // the picture area rectangle

                                                                                Rectangle rect = new Rectangle(bounds.X-1,

                                                                                                bounds.Y,

                                                                                                IMAGE_BUFFER_SIZE - 3,

                                                                                                bounds.Height);

 

                                                                                // Create Gradient brush, using system colors

                                                                                Brush b = new LinearGradientBrush(rect,

                                                                                                Color.FromArgb(30,SystemColors.InactiveCaption),

                                                                                                SystemColors.ActiveCaption,

                                                                                                0f,

                                                                                                false);

 

                                                                                // Draw the rect

                                                                                _graphics.FillRectangle(b, rect);

                                                                }

                                                public void DrawSeperator( Rectangle bounds )

                                                {

                                                                // create the seperator line pen

                                                                Pen pen = new Pen(SystemColors.ControlDark) ;

 

                                                                // calculate seperator boundaries

                                                                int xLeft = bounds.Left + IMAGE_BUFFER_SIZE ;

                                                                int xRight = xLeft + bounds.Width ;

                                                                int yCenter = bounds.Top  + (bounds.Height / 2) ;

 

                                                                // draw a seperator line and return

                                                                _graphics.DrawLine(pen, xLeft, yCenter, xRight, yCenter) ;

                                                }

                                               

                                                #endregion

                                               

                                                #region Private Members

 

                                                private void DrawMenuText ( Rectangle bounds, bool selected )

                                                {

                                                                // use system fonts and colors to select the menu brush so the menu

                                                                // will appear correctly for any desktop theme

                                                                Font menuFont = SystemInformation.MenuFont ;

                                                                SolidBrush menuBrush = null ;

                                                                if ( _menuItem.Enabled == false )

                                                                                menuBrush = new SolidBrush( SystemColors.GrayText ) ;

                                                                else

                                                                {

                                                                                menuBrush = new SolidBrush( SystemColors.MenuText ) ;

                                                                }

                                                               

                                                                // draw the menu text

                                                                StringFormat sfMenu = new StringFormat() ;

                                                                sfMenu.HotkeyPrefix = System.Drawing.Text.HotkeyPrefix.Show ;

                                                               _graphics.DrawString( _menuItem.Text, menuFont, menuBrush, bounds.Left + IMAGE_BUFFER_SIZE, bounds.Top + ((bounds.Height - menuFont.Height) / 2), sfMenu ) ;

 

                                                                // if the menu has a shortcut, then also

                                                                // draw the shortcut right aligned

                                                                if ( this.IsTopLevel() != true || this.HasShortcut() == false )

                                                                {

                                                                                StringFormat sfShortcut = new StringFormat() ;

                                                                                sfShortcut.HotkeyPrefix = System.Drawing.Text.HotkeyPrefix.Show ;

                                                                                sfShortcut.FormatFlags |= StringFormatFlags.DirectionRightToLeft;

                                                                                int shortcutWidth = (int) _graphics.MeasureString( this.ShortcutText, menuFont, 1000, sfShortcut).Width ;

                                                                                _graphics.DrawString(this.ShortcutText, menuFont, menuBrush, (bounds.Width) - LBUFFER_WIDTH , bounds.Top + ((bounds.Height - menuFont.Height) / 2), sfShortcut);

                                                                }

                                                }                                              

                                               

                                                private void DrawCheckBox( Rectangle bounds )

                                                {

                                                                // use the very handy ControlPaint object to paint

                                                                // a checkbox. ButtonState is a bitwise flat that can be built

                                                                // to accomodate style and state appearance

                                                                ButtonState btnState = ButtonState.Flat ;

                                                               

                                                                if ( _menuItem.Checked == true )

                                                                                btnState = btnState | ButtonState.Checked ;

                                                               

                                                                if ( _menuItem.Enabled == false )

                                                                                btnState = btnState | ButtonState.Inactive ;

                                                               

                                                                // draw the checkbox

                                                                ControlPaint.DrawCheckBox(_graphics, bounds.Left + SBORDER_WIDTH, bounds.Top + ((bounds.Height - IMAGE_HEIGHT) / 2), IMAGE_WIDTH, IMAGE_HEIGHT, btnState ) ;

                                                }

                                               

                                                private void DrawImage( Image menuImage, Rectangle bounds )

                                                {

                                                                // if the menu item is enabled, then draw the image normally

                                                                // otherwise draw it as disabled

                                                                if ( _menuItem.Enabled == true )

                                                                                _graphics.DrawImage(menuImage, bounds.Left + SBORDER_WIDTH, bounds.Top + ((bounds.Height - IMAGE_HEIGHT) / 2), IMAGE_WIDTH, IMAGE_HEIGHT ) ;      

                                                                else

                                                                                ControlPaint.DrawImageDisabled(_graphics, menuImage, bounds.Left + SBORDER_WIDTH, bounds.Top + ((bounds.Height - IMAGE_HEIGHT) / 2), SystemColors.Menu ) ;

                                                }

                                               

                                                private void DrawArrow( Image menuImage, Rectangle bounds )

                                                {

                                                                _graphics.DrawImage(menuImage, bounds.Left + bounds.Width - ARROW_WIDTH, bounds.Top + ((bounds.Height - IMAGE_HEIGHT) / 2), IMAGE_WIDTH, IMAGE_HEIGHT ) ;      

                                                }

                                               

                                                #endregion

                                }

                               

                                #endregion

                }

}

注:以上代码是我利用CodeProject上的代码经自己稍微修改作成的

posted on 2006-11-28 14:06  everx  阅读(400)  评论(0编辑  收藏  举报