C#自定义控件简介(二)

      接着上一篇文章讲,这次来说说C#自定义控件中的扩展控件(Extended Controls)的创建和使用。所谓的扩展控件就是在原有控件的基础上派生出新的控件,为了让大家更好的理解,这次就用C#中最基本的组件——Button来演示。最终的效果如下:

 

      测试Demo下载

 

好了,下面来说说创建的步骤:

一. 创建一个Windows窗口控件库项目,命名为MyButton;

二.编写控件代码,代码如下:(请自行添加System.Reflection命名空间)

namespace MyButton
{
    [DefaultEvent("Click"), ToolboxBitmap(typeof(MyButton),"Res.MyICO.ico")]
    public partial class MyButton : Button
    {
        private State _buttonState = State.Normal;

        //从资源文件载入图片
        private Image _normalImg = Image.FromStream(Assembly.GetExecutingAssembly().GetManifestResourceStream(@"MyButton.Res.btn_normal.png"));
        private Image _highLightImg = Image.FromStream(Assembly.GetExecutingAssembly().GetManifestResourceStream(@"MyButton.Res.btn_highlight.png"));
        private Image _downImg = Image.FromStream(Assembly.GetExecutingAssembly().GetManifestResourceStream(@"MyButton.Res.btn_down.png"));
        private Image _focusedImg = Image.FromStream(Assembly.GetExecutingAssembly().GetManifestResourceStream(@"MyButton.Res.btn_focus.png"));
        private Image _disabledImg = Image.FromStream(Assembly.GetExecutingAssembly().GetManifestResourceStream(@"MyButton.Res.btn_disabled.png"));

        #region  Properties
        [Category("自定义属性"),Description("控件的正常背景图片")]
        public Image NormalImg
        {
            get
            {
                return _normalImg;
            }
            set
            {
                _normalImg = value;
                BackgroundImage = value;
            }
 
        }

        [Category("自定义属性"), Description("当鼠标进入控件的可见部分是的背景图片")]
        public Image HighLightImg
        {
            get
            {
                return _highLightImg;
            }
            set
            {
                _highLightImg = value;
            }
        }

        [Category("自定义属性"), Description("当控件被按下时的背景图片")]
        public Image DownImg
        {
            get
            {
                return _downImg;
            }
            set
            {
                _downImg = value;
            }
        }

        [Category("自定义属性"), Description("当控件拥有焦点时的背景图片")]
        public Image FocusedImg
        {
            get
            {
                return _focusedImg;
            }
            set
            {
                _focusedImg = value;
            }
        }

        [Category("自定义属性"), Description("控件禁止时的背景图片")]
        public Image DisabledImg
        {
            get
            {
                return _disabledImg;
            }
            set
            {
                _disabledImg = value;
            }
        }

        #endregion  Properties

        //===============================================================================================

        // Constructor
        public MyButton(): base()
        {
            SetStyle(ControlStyles.UserPaint, true);
            SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            SetStyle(ControlStyles.ResizeRedraw, true);
            SetStyle(ControlStyles.SupportsTransparentBackColor, true);
        }

        #region  OverrideMethods
        protected override void OnMouseEnter(EventArgs e)
        {
            base.OnMouseEnter(e);
            _buttonState = State.Highlight;
        }

        protected override void OnMouseLeave(EventArgs e)
        {
            if (_buttonState == State.Highlight && Focused)
            {
                _buttonState = State.Focused;

            }
            else if (_buttonState == State.Focused)
            {
                _buttonState = State.Focused;
            }
            else
            {
                _buttonState = State.Normal;
            }
            base.OnMouseLeave(e);
        }

        protected override void OnMouseDown(MouseEventArgs mevent)
        {

            if (mevent.Button == MouseButtons.Left && mevent.Clicks == 1)
            {
                _buttonState = State.Down;
                base.OnMouseDown(mevent);
            }
        }

        protected override void OnMouseUp(MouseEventArgs mevent)
        {
            if (mevent.Button == MouseButtons.Left && mevent.Clicks == 1)
            {
                if (ClientRectangle.Contains(new Point(mevent.X, mevent.Y)))
                {
                    _buttonState = State.Highlight;
                }
                else
                {
                    _buttonState = State.Focused;
                }
                base.OnMouseUp(mevent);
            }
        }

        // The event of OnLeave and OnEnter to make object lost focus or get focus 
        protected override void OnLeave(EventArgs e)
        {
            _buttonState = State.Normal;
            base.OnLeave(e);
        }

        protected override void OnEnter(EventArgs e)
        {
            _buttonState = State.Focused;
            base.OnEnter(e);
        }

        protected override void OnPaint(PaintEventArgs pevent)
        {
            base.OnPaint(pevent);
            base.OnPaintBackground(pevent);

            Graphics g = pevent.Graphics;

            if (Enabled == false)
            {
                _buttonState = State.Disabled;
            }

            switch (_buttonState)
            {
                case State.Highlight:
                    g.DrawImage(_highLightImg, new Rectangle(0, 0, Width, Height));
                    break;
                case State.Down:
                    g.DrawImage(_downImg, new Rectangle(0, 0, Width, Height));
                    break;
                case State.Focused:
                    g.DrawImage(_focusedImg, new Rectangle(0, 0, Width, Height));
                    break;
                case State.Disabled:
                    g.DrawImage(_disabledImg, new Rectangle(0, 0, Width, Height));
                    break;
                default:
                    g.DrawImage(_normalImg, new Rectangle(0, 0, Width, Height));
                    break;
            }

            DrawText(g);
        }

        protected override void Dispose(bool disposing)
        {
            if (_normalImg != null || _highLightImg != null || _downImg != null || _focusedImg != null || _disabledImg != null)
            {
                _normalImg.Dispose();
                _highLightImg.Dispose();
                _downImg.Dispose();
                _focusedImg.Dispose();
                _disabledImg.Dispose();
            }
            base.Dispose(disposing);
        }
        #endregion  OverrideMethods

        #region  PrivateMethods
        private void DrawText(Graphics g)
        {
            int x = 0;
            int y = 0;
            Size s = g.MeasureString(Text, Font).ToSize();
            x = (Width - s.Width) / 2;
            y = (Height - s.Height) / 2;
            g.DrawString(Text, Font, Brushes.Black, new Point(x, y));
        }
        #endregion  PrivateMethods

        #region Enum
        internal enum State
        {
            Normal,  //正常

            Highlight,  // 鼠标进入

            Down,  //鼠标按下

            Focused,  // 获得焦点

            Disabled  //控件禁止
        }
        #endregion  Enum
    }
}

三.删除有VS设计器自动生成的代码文件MyButton.Designer.cs。

四.此时按F5测试项目时会发现出现异常,因为这个时候把启动项设成了控件的项目,但是启动项必须是可运行的项目(包含Form窗体的),解决方法是找一个包含Form窗体的宿主项目,可以往解决方案中添加已有的项目,再把其设置为启动项,这里我在解决方案中创建了新的Windows窗体项目Test,并设置为启动项。此时按F5即可。

方案布局如下:

 

五.此时我们的自定义控件就生成了,是个dll文件,这里建议看下我的上一篇文章C#自定义控件简介(一),因为待会可能会用能。好了我们现在用宿主项目来测试下控件是否如设计的那样,把DLL控件加载到宿主项目的工具箱中,或者直接把dll拖放到工具箱中,但是当把控件添加到宿主项目的Form1中,你会发现有错误。这又是什么情况呢???容我慢慢的向你道来。

        代码的前几行是从资源文件中导入我们需要的图片,但是在我们的解决方案中却找不到Res这个资源文件夹,所以问题就出现在这里,解决办法和简单,在解决方案中添加名为Res的文件夹,并把需要的图片文件放到文件夹中,有个最重要的步骤别忘了,就是把各个图片的属性栏的生成操作选项全部改成嵌入的资源,这样导入的图片才会被项目所使用。这一步也可以再写代码时同步完成。更改后项目布局如下:

 

        现在自定义的控件可以像一般的控件进行拖放使用了。由于本篇文章的侧重点为如何创建和使用自定义控件,所以关于代码我就简单的说下:

重写基类的方法来对控件的各个状态进行判断与赋值,并根据状态的不同绘制不同的背景图片,设置控件不同状态时图片的属性,便于用户根据自己的喜好更换背景图片,代码中用到了许多自定义控件的的特性,如下表所示:

 

DefaultEven在设计界面时双击控件时产生的默认事件
ToolboxBitmap设置自定义控件在工具箱中显示的图片
Category设置在属性栏中属性所处的类别,如“外观”,“设计”,“行为”等
Description设置控件属性时,在属性窗口底端显示的该属性的描述
DefaultValue设置控件属性的默认值

 

以上只是实现了button控件的基本属性,起个抛砖引玉的作用,更好的设计还望读者自行编写扩展,如若有不足之处,还请各位批评指正。

 

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值