(转)C# WinForm控件开发和美化(2)——PanelEx控件

Posted on 2011-08-01 22:36  pumeifen  阅读(1419)  评论(0编辑  收藏  举报

  今天介绍WinForm控件开发和美化系列的第一个控件Panel控件。这个控件本身比较简单,主要就是用到了一些GDI+的知识。作为这个系列的第一个控件,在这里也介绍一些控件开发和GDI+的内容。

      在看过这篇系列文章后,如果您有什么好的意见和建议,请给我留言。 

一、效果图

 

二、实现代码

namespace Lt_WinControls

{

    [DefaultProperty("Visible"), DefaultEvent("Click")]

    [ToolboxItem(true)]

    [ToolboxBitmap(typeof(PanelEx), "Resources.PanelEx.bmp")]

    [Description("表示一个可以自定义边框样式的Panel控件。")]

    //[Designer(typeof(PanelExDesigner))]

    //[Docking(DockingBehavior.Ask)]

    public class PanelEx : Panel

{

        #region 属性

        bool _topLeft = true;

        [DefaultValue(true)]

        [Description("当CornerMode为Round时,是否显示左上角"), Category("自定义外观")]

        public bool TopLeft

        {

            get { return _topLeft; }

            set

            {

                _topLeft = value;

                base.Invalidate();

            }

        }

 

        bool _topRight = true;

        [DefaultValue(true)]

        [Description("当CornerMode为Round时,是否显示右上角"), Category("自定义外观")]

        public bool TopRight

        {

            get { return _topRight; }

            set

            {

                _topRight = value;

                base.Invalidate();

            }

        }

 

        bool _bottomLeft = true;

        [DefaultValue(true)]

        [Description("当CornerMode为Round时,是否显示左下角"), Category("自定义外观")]

        public bool BottomLeft

        {

            get { return _bottomLeft; }

            set

            {

                _bottomLeft = value;

                base.Invalidate();

            }

        }

        bool _bottomRight = true;

        [DefaultValue(true)]

        [Description("当CornerMode为Round时,是否显示右下角"), Category("自定义外观")]

        public bool BottomRight

        {

            get { return _bottomRight; }

            set

            {

                _bottomRight = value;

                base.Invalidate();

            }

        }

 

        private Color _borderColor = Color.Black;

        [DefaultValue(typeof(Color), "Black")]

        [Description("设置边框线的颜色"), Category("自定义外观")]

        public Color BorderColor

        {

            get { return _borderColor; }

            set

            {

                _borderColor = value;

                base.Invalidate();

            }

        }

        private GradientMode _gradientMode = GradientMode.None;

        [DefaultValue(typeof(GradientMode), "0")]

        [Description("用渐变色来填充背景时的填充方式"), Category("自定义外观")]

        public GradientMode GradientMode

        {

            get { return _gradientMode; }

            set

            {

                _gradientMode = value;

                base.Invalidate();

            }

        }

        [Browsable(false)]

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]

        public override Color BackColor

        {

            get

            {

                return Color.Transparent;

            }

        }

        private Color _backColor1 = Color.White;

        [DefaultValue(typeof(Color), "White")]

        [Description("控件的背景色1(若同时设置两个背景色,就是会用渐变色来填充背景)"), Category("自定义外观")]

        public Color BackColor1

        {

            get { return _backColor1; }

            set

            {

                _backColor1 = value;

                base.Invalidate();

            }

        }

        private Color _backColor2 = Color.White;

        [DefaultValue(typeof(Color), "White")]

        [Description("控件的背景色2,当GradientMode不为None时有效"), Category("自定义外观")]

        public Color BackColor2

        {

            get { return _backColor2; }

            set

            {

                _backColor2 = value;

                base.Invalidate();

            }

        }

        private int _borderWidth = 1;

        [DefaultValue(1)]

        [Description("设置边框线的宽度"), Category("自定义外观")]

        public int BorderWidth

        {

            get { return _borderWidth; }

            set

            {

                if (value >= 0)

                {

                    _borderWidth = value;

                    SetPadding();

                    base.Invalidate();

                }

            }

        }

 

        private DashStyle _borderStyle = DashStyle.Solid;

        [DefaultValue(typeof(DashStyle), "0")]

        [Description("设置边框线样式"), Category("自定义外观")]

        public new DashStyle BorderStyle

        {

            get { return _borderStyle; }

            set

            {

                _borderStyle = value;

                base.Invalidate();

            }

        }

 

        private int _roundSize = 15;

        /// <summary>

        /// 设置边角大小

        /// </summary>

        [DefaultValue(15)]

        [Description("当CornerMode为Round时,设置边角大小"), Category("自定义外观")]

        public int RoundSize

        {

            get { return _roundSize; }

            set

            {

                if (value > 0)

                {

                    _roundSize = value;

                    base.Invalidate();

                }

            }

        }

 

        private CornerMode _cornerMode = CornerMode.Corner;

        /// <summary>

        /// 设置边角样式

        /// </summary>

        [DefaultValue(typeof(CornerMode), "2")]

        [Description("设置边角样式"), Category("自定义外观")]

        public CornerMode CornerMode

        {

            get { return _cornerMode; }

            set

            {

                _cornerMode = value;

                SetPadding();

                base.Invalidate();

            }

        }

 

        private bool _leftBorder = true;

        /// <summary>

        /// 左边框是否显示

        /// </summary>

        [DefaultValue(true)]

        [Description("当CornerMode为Corner时,是否显示左边框"), Category("自定义外观")]

        public bool LeftBorder

        {

            get { return _leftBorder; }

            set

            {

                _leftBorder = value;

                base.Invalidate();

            }

        }

 

        private bool _rightBorder = true;

        /// <summary>

        /// 是否显示右边框

        /// </summary>

        [DefaultValue(true)]

        [Description("当CornerMode为Corner时,是否显示右边框"), Category("自定义外观")]

        public bool RightBorder

        {

            get { return _rightBorder; }

            set

            {

                _rightBorder = value;

                base.Invalidate();

            }

        }

 

        private bool _topBorder = true;

        /// <summary>

        /// 是否显示上边框

        /// </summary>

        [DefaultValue(true)]

        [Description("当CornerMode为Corner时,是否显示上边框"), Category("自定义外观")]

        public bool TopBorder

        {

            get { return _topBorder; }

            set

            {

                _topBorder = value;

                base.Invalidate();

            }

        }

 

        private bool _bottomBorder = true;

        /// <summary>

        /// 是否显示下边框

        /// </summary>

        [DefaultValue(true)]

        [Description("当CornerMode为Corner时,是否显示下边框"), Category("自定义外观")]

        public bool BottomBorder

        {

            get { return _bottomBorder; }

            set

            {

                _bottomBorder = value;

                base.Invalidate();

            }

        }

        #endregion

 

        #region 构造函数

        /// <summary>

        /// 构造函数

        /// </summary>

        public PanelEx()

        {

            base.ResizeRedraw = true;

            this.BackColor = Color.Transparent;

        }

        #endregion

 

        private void SetPadding()

        {

            int left = this.Padding.Left;

            int right = this.Padding.Right;

            int top = this.Padding.Top;

            int bottom = this.Padding.Bottom;

            if (this.CornerMode == CornerMode.None)

            {

                left = 0;

                right = 0;

                top = 0;

                bottom = 0;

            }

            else

            {

                if (this.Padding.Left < this.BorderWidth)

                {

                    left = this.BorderWidth;

                }

                if (this.Padding.Right < this.BorderWidth)

                {

                    right = this.BorderWidth;

                }

                if (this.Padding.Top < this.BorderWidth)

                {

                    top = this.BorderWidth;

                }

                if (this.Padding.Bottom < this.BorderWidth)

                {

                    bottom = this.BorderWidth;

                }

            }

            this.Padding = new Padding(left, top, right, bottom);

        }

 

        #region 控件重绘事件

        /// <summary>

        /// 控件重绘事件

        /// </summary>

        /// <param name="e"></param>

        protected override void OnPaint(PaintEventArgs e)

        {

            base.OnPaint(e);

            Graphics g = e.Graphics;

            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;

            Rectangle rec = new Rectangle(0, 0, this.Width, this.Height);

            Pen pen = new Pen(BorderColor, BorderWidth);

            pen.DashStyle = BorderStyle;

            GraphicsPath path = CreateRound(rec, RoundSize, this.TopLeft, this.TopRight, this.BottomLeft, this.BottomRight);

 

            //绘制背景

            if (this.GradientMode == GradientMode.None)

            {

                using (Brush brush2 = new SolidBrush(this.BackColor1))

                {

                    if (this.CornerMode == CornerMode.Round)

                    {

                        g.FillPath(brush2, path);

                    }

                    else

                    {

                        g.FillRectangle(brush2, rec);

                    }

                }

            }

            else

            {

                if (this.CornerMode == CornerMode.Round)

                {

                    DrawGradient(g, rec, path, this.BackColor1, this.BackColor2, this._gradientMode);

                }

                else

                {

                    DrawGradient(g, rec, this.BackColor1, this.BackColor2, this._gradientMode);

                }

            }

 

            //绘制边框

            if (BorderWidth > 0)

            {

                switch (CornerMode)

                {

                    case CornerMode.None:

                        break;

                    case CornerMode.Corner:

                        if (LeftBorder)

                        {

                            g.DrawLine(pen, 0, 0, 0, this.Height - 1);

                        }

                        if (BottomBorder)

                        {

                            g.DrawLine(pen, 0, this.Height - 1, this.Width - 1, this.Height - 1);

                        }

                        if (RightBorder)

                        {

                            g.DrawLine(pen, Width - 1, this.Height - 1, this.Width - 1, 0);

                        }

                        if (TopBorder)

                        {

                            g.DrawLine(pen, this.Width - 1, 0, 0, 0);

                        }

                        break;

                    case CornerMode.Round:

                        g.DrawPath(pen, path);

                        break;

                }

            }

        }

        #endregion

 

        public static GraphicsPath CreateRound(Rectangle rect, int radius, bool topLeft, bool topRight, bool bottomLeft,bool bottomRight)

        {

            rect.Width -= 1;

            rect.Height -= 1;

 

            GraphicsPath roundRect = new GraphicsPath();

            //顶端

            roundRect.AddLine(rect.Left + radius / 2, rect.Top, rect.Right - radius / 2, rect.Top);

            //右上角

            if (topRight)

            {

                roundRect.AddArc(rect.Right - radius, rect.Top, radius, radius, 270, 90);

            }

            else

            {

                roundRect.AddLine(rect.Right - radius / 2, rect.Top, rect.Right, rect.Top);

                roundRect.AddLine(rect.Right, rect.Top, rect.Right, rect.Top + radius / 2);

            }

 

            //右边

            roundRect.AddLine(rect.Right, rect.Top + radius / 2, rect.Right, rect.Bottom - radius / 2);

 

            //右下角

            if (bottomRight)

            {

                roundRect.AddArc(rect.Right - radius, rect.Bottom - radius, radius, radius, 0, 90);

            }

            else

            {

                roundRect.AddLine(rect.Right, rect.Bottom - radius / 2, rect.Right, rect.Bottom);

                roundRect.AddLine(rect.Right, rect.Bottom, rect.Right - radius / 2, rect.Bottom);

            }

 

            //底边

            roundRect.AddLine(rect.Right - radius / 2, rect.Bottom, rect.Left + radius / 2, rect.Bottom);

 

            //左下角

            if (bottomLeft)

            {

                roundRect.AddArc(rect.Left, rect.Bottom - radius, radius, radius, 90, 90);

            }

            else

            {

                roundRect.AddLine(rect.Left + radius / 2, rect.Bottom, rect.Left, rect.Bottom);

                roundRect.AddLine(rect.Left, rect.Bottom, rect.Left, rect.Bottom - radius / 2);

            }

 

            //左边 不需要了

            // roundRect.AddLine(rect.Left, rect.Top + radius / 2, rect.Left, rect.Bottom - radius / 2);

 

            //左上角

            if (topLeft)

            {

                roundRect.AddArc(rect.Left, rect.Top, radius, radius, 180, 90);

            }

            else

            {

                roundRect.AddLine(rect.Left, rect.Top + radius / 2, rect.Left, rect.Top);

                roundRect.AddLine(rect.Left, rect.Top, rect.Left + radius / 2, rect.Top);

            }

            //闭合图像

            roundRect.CloseAllFigures();

            return roundRect;

        }

 

 

        public static void DrawGradient(Graphics e, Rectangle rect, GraphicsPath path, Color color1, Color color2,GradientMode mode)

        {

            LinearGradientMode backwardDiagonal = LinearGradientMode.BackwardDiagonal;

            if (mode == GradientMode.Vertical)

            {

                backwardDiagonal = LinearGradientMode.Vertical;

            }

            else if (mode == GradientMode.Horizontal)

            {

                backwardDiagonal = LinearGradientMode.Horizontal;

            }

            else if (mode == GradientMode.BackwardDiagonal)

            {

                backwardDiagonal = LinearGradientMode.BackwardDiagonal;

            }

            else if (mode == GradientMode.ForwardDiagonal)

            {

                backwardDiagonal = LinearGradientMode.ForwardDiagonal;

            }

            LinearGradientBrush brush = new LinearGradientBrush(rect, color1, color2, backwardDiagonal);

            e.FillPath(brush, path);

            brush.Dispose();

        }

 

        public static void DrawGradient(Graphics e, Rectangle rect, Color color1, Color color2, GradientMode mode)

        {

            LinearGradientMode backwardDiagonal = LinearGradientMode.BackwardDiagonal;

            if (mode == GradientMode.Vertical)

            {

                backwardDiagonal = LinearGradientMode.Vertical;

            }

            else if (mode == GradientMode.Horizontal)

            {

                backwardDiagonal = LinearGradientMode.Horizontal;

            }

            else if (mode == GradientMode.BackwardDiagonal)

            {

                backwardDiagonal = LinearGradientMode.BackwardDiagonal;

            }

            else if (mode == GradientMode.ForwardDiagonal)

            {

                backwardDiagonal = LinearGradientMode.ForwardDiagonal;

            }

            LinearGradientBrush brush = new LinearGradientBrush(rect, color1, color2, backwardDiagonal);

            e.FillRectangle(brush, rect);

            brush.Dispose();

        }

    }

 

 

    public enum GradientMode

    {

        /// <summary>

        /// 无填充样式

        /// </summary>

        None = 0,

        /// <summary>

        /// 垂直填充

        /// </summary>

        Vertical = 1,

        /// <summary>

        /// 水平填充

        /// </summary>

        Horizontal = 2,

        /// <summary>

        /// 右上角到左下角

        /// </summary>

        BackwardDiagonal = 3,

        /// <summary>

        /// 左上角到右下角

        /// </summary>

        ForwardDiagonal = 4

    }

 

    public enum CornerMode

    {

        /// <summary>

        /// 没有边框

        /// </summary>

        None = 0,

 

        /// <summary>

        /// 指定圆角

        /// 此时的边框设置以上边框为准

        /// </summary>

        Round = 1,

 

        /// <summary>

        /// 指定尖角

        /// </summary>

        Corner = 2,

    }

}

 三、控件设计知识介绍

  1、类的属性集

    

    定义控件的默认属性和默认事件:

    设置默认属性后,在设计时选中该控件的话,属性栏中的默认属性会变成灰色;

    设置默认事件后,在设计时双击该控件会自动生成默认的事件代码,比如双击这个控件后会生成Click事件的代码

    //[DefaultProperty("Visible"), DefaultEvent("Click")]

    下面这个属性设置这个控件是否在控件工具箱中显示

    [ToolboxItem(true)]

    下面这个属性设置这个控件显示在工具箱中的图标,可以设置成自己定义的图标

    [ToolboxBitmap(typeof(PanelEx), "Resources.PanelEx.bmp")]

    下面的属性设置在工具箱中显示的控件的提示内容

    [Description("表示一个可以自定义边框样式的Panel控件。")]

    下面的属性设置控件的设计类,就是在设置时显示在控件右上角的小三角里面的内容,panle控件设置了设计类比较奇怪,无法当做容器来使用。

    所以在这里就不介绍控件的设计类了,这部分放到后面的控件来介绍

    //[Designer(typeof(PanelExDesigner))]

    下面是属性设置控件默认的停靠属性,Ask表示有用户来设置停靠方式

     //[Docking(DockingBehavior.Ask)]

     public class PanelEx : Panel

{

     }

2、属性的属性集

         即使设置了默认值,在声明字段的时候或构造函数里面还是要对字段进行赋值,不然默认值的设置就没有意义了

         private Color _backColor1 = Color.White;

         设置属性的默认值,这个地方给很多人造成了误解,认为设置了默认属性值,在代码生成的时候就自动生成默认的值了,

         其实不是这样,设置默认值有两个作用:

         一是如果设置的值和默认值相同的话,在控件的属性列表中就不会加粗显示这个值;

        而是如果设置的值和默认值相同的话,在控件的生成过程中不生成对该属性的赋值代码(这一点很关键)。

        [DefaultValue(typeof(Color), "White")]

        下面的属性设置这个属性在控件的属性窗口中的分类和提示信息

        [Description("控件的背景色1(若同时设置两个背景色,就是会用渐变色来填充背景)"), Category("自定义外观")]

        public Color BackColor1

        {

            get { return _backColor1; }

            set

            {

                _backColor1 = value;

                base.Invalidate();

            }

        }

     由于在自定义控件中,已经设置了控件的背景色,并且我希望控件原来的背景色一直是透明的,所以用下面的方法来屏蔽控件本身的属性BackColor

     这个属性设置控件的该属性不显示在在控件的属性窗口中

    [Browsable(false)]

    表示在控件生成的时候不生成这个属性的代码

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]

    public override Color BackColor

    {

          get

          {

               让属性的值一直返回透明色,这样你即使在客户端代码中设置了这个属性,也是无效的

               return Color.Transparent;

          }

     }

    在这里我只介绍这个项目中用到的一些内容,还有一些内容会在以后用到的时候在给大家介绍。

  比如: 一些属性本身就是一个类,这个类本身也包含很多的属性,我们希望在代码生成的时候不生成这个类本身的代码,而是希望生成这个类的子属性的代码。

        并且在属性窗口中看到的也是这个类的子属性,这些都会在后面的内容介绍