程序员的知识教程库

网站首页 > 教程分享 正文

C#学习随笔—自定义控件(面板)(c#自定义控件按钮)

henian88 2025-05-03 14:15:55 教程分享 5 ℃ 0 评论

最近一直在研究C#的自定义控件,因为在实际开发使用中发现C# winform的自定义控件并不满足需求。因此,自己在逐步开始接触自定义控件,并将其记录。

首先,先完成一个最基本控件的实现,即一个面板,说起来就是一个框,这个框,可以调节里面的填充颜色,设置框线的宽度,虚实线类型,是方形,圆形或者椭圆形等。

涉及的C#第一个概念:get和set访问器,我们在使用控件属性时,会经常用到,属性的设置以及读取,该访问器就帮助我们实现这一功能,举例如下:(如我想要设置是否显示边框)

private bool _isBorderShow = true;

public bool IsBorderShow
{
  get
  {
    return this._isBorderShow;
  }
  set
  {
    this._isBorderShow = value;
  }
}

基本格式如上所示,首先肯定需要定义一个参数来存储该属性,get访问器就是会返回该参数,set访问器会设置该参数,注意,set访问器有一个隐式参数,即value。value持有需要保存的数据。因此,value可以直接使用,而不需要重新定义。当然,该属性是要外部访问的,因此设置为PUBLIC。

之后呢,只需要在Visual Studio建立用户控件即可,因为我们是要建基类控件,因此还需要继承IContainerControl类,默认的用户控件仅仅继承了UserControl类。因此修改如下:

public partial class SimplyCtrlBase: UserControl,IContainerControl  //多接口控件,UserControl:作为该控件的模板接口,IContainerControl:可以使该自定义控件作为其他控件的父类
{
	//增加控件的属性和方法
  
  //用户控件的初始化
  public SimplyCtrlBase()
  {
    InitializeComponent();//控件的初始化
  }
}

用户控件的属性比较容易,只需要调用get和set访问器即可实现,那么控件的样子需要怎么弄呢?其实就是重绘,因此需要对控件的绘制函数进行重写。

那么我们需要实现怎么样的控件呢?见下图:

上面就是我想要实现的面板类型,可以给用户足够的开放度,选择圆形,长方形,椭圆形。可以设置渐变的背景色,可以设置框线的类型,可以设置框线的宽度,等等。

重绘函数的实现如下:

protected override void OnPaint(PaintEventArgs e)
{
  //写自己的重绘图形即可。
	base.OnPaint(e);
}

剩下的也没啥好说的,直接上代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Drawing.Drawing2D;

namespace MyLib_Simply
{
  [Designer("System.Windows.Forms.Design.ParentControlDesigner, System.Design", typeof(System.ComponentModel.Design.IDesigner))]
  public partial class SimplyCtrlBase: UserControl,IContainerControl  //多接口控件,UserControl:作为该控件的模板接口,IContainerControl:可以使该自定义控件作为其他控件的父类
  {
    //方形边框是否显示圆弧
    private bool _isRoundCorner = true;
    [Description("Round Corner flag,Only available for RECTANGLE BLOCK"),Category("UserDefinedBase")]//Category:显示类别,Description:属性或者方法描述
    public bool IsRoundCorner
    {
      get {return this._isRoundCorner;}
      set {this._isRoundCorner = value;}
    }
    
    //设置边框圆弧角度
    private int _roundCorner = 20;
    [Description("Round Corner Property for Rectangle Block,In fact, it means diameter for round corner"),Category("UserDefinedBase")]
    public int RoundCorner
    {
      get {return this._roundCorner;      }
      set {this._roundCorner = value;}
    }

    //设置是否显示框线
    private bool _isBorderShow = true;
    [Description("Whether is Border showing or not"),Category("UserDefinedBase")]
    public bool IsBorderShow
    {
      get{return this._isBorderShow;}
      set{this._isBorderShow = value;}
    }
    
    //设置框线宽度
    private int _borderWidth =2;
    [Description("Border Width"),Category("UserDefinedBase")]
    public int BorderWidth
    {
      get{return this._borderWidth;}
      set{ this._borderWidth = value;}
    }

    //设置框线颜色
    private Color _borderColor = Color.Black;
    [Description("Border Color"), Category("UserDefinedBase")]
    public Color BorderColor
    {
      get{ return this._borderColor;}
      set{this._borderColor = value; }
    }

    //设置框线类型,实线还是虚线
    private DashStyle _borderDashStyle = DashStyle.Solid;
    [Description("Border Line DashStyle"),Category("UserDefinedBase")]
    public DashStyle BorderDashStyle
    {
      get{return this._borderDashStyle;}
      set{this._borderDashStyle = value;}
    }

    //设置面板类型,方形还是椭圆形
    public enum block_type_t
    {
      BLOCK_RECTANGLE,
        BLOCK_OVAL,
    }
      
    //设置边框类型
    private block_type_t _blockType = block_type_t.BLOCK_RECTANGLE;
    [Description("Block Type"), Category("UserDefinedBase")]
    public block_type_t BlockType  //必须有一个访问器,Get或者Set
    {
      get{ return this._blockType;}
      set {this._blockType = value;}
    }

    //设置面板背景色是否渐变
    private bool _isKindsColor = true;
    [Description("Kinds of Color Flag for Block Back Color"), Category("UserDefinedBase")]
    public bool IsKindsColor
    {
      get { return this._isKindsColor; }
      set { this._isKindsColor = value; }
    }

    //渐变色的第二种颜色,BackColor为第一种颜色
    private Color _alternateColor = SystemColors.Control;
    [Description("Alternate Color for linear kinds of color,i.e. from BackColor to Alternate Color"),Category("UserDefinedBase")]
    public Color AlternateColor
    {
      get{return this._alternateColor;}
      set{this._alternateColor = value;}
    }

    //控件初始化
    public SimplyCtrlBase()
    {
      InitializeComponent();
      base.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer|ControlStyles.ResizeRedraw, true);
    	//开启双缓冲
    }
        
    //控件重绘
    protected override void OnPaint(PaintEventArgs e)
    {
      if (this.Visible)
      {
        switch (this._blockType)
        {
          case block_type_t.BLOCK_RECTANGLE:
          default:
            GraphicsPath path = new GraphicsPath();
            Pen pen = new Pen(this._borderColor, (float)(this._borderWidth));
            pen.DashStyle = this._borderDashStyle;
            if (this._isRoundCorner)
            {
              RectangleF rect = new Rectangle(0, 0, this.Width, this.Height);
              path = GetRoundRectPath(rect, this._roundCorner, 0);
              base.Region = new Region(path);
              Rectangle ClientRect = this.ClientRectangle;
              path = GetRoundRectPath(ClientRect, this._roundCorner, (float)((this._borderWidth)/2.0));
            }
            else
            {
              path.AddRectangle(this.ClientRectangle);
              path.CloseFigure();
              base.Region = new Region(path);
              path.AddRectangle(new RectangleF((float)((this._borderWidth)/2.0), (float)((this._borderWidth) / 2), this.ClientRectangle.Width -  (this._borderWidth), this.ClientRectangle.Height - (this._borderWidth )));
              path.CloseFigure();
            }
            e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
            if (this._isKindsColor)
            {
              //背景色的线性渐变
              LinearGradientBrush brush = new LinearGradientBrush(e.ClipRectangle, this.BackColor, this._alternateColor, 90f);
              e.Graphics.FillRectangle(brush, e.ClipRectangle);
              brush.Dispose();// release resource
            }
            else
            {
              e.Graphics.FillPath(new SolidBrush(this.BackColor), path);
            }
              if (this._isBorderShow)
              {
                e.Graphics.DrawPath(pen, path);
              }
            pen.Dispose();
            break;
          
          case block_type_t.BLOCK_OVAL:
            path = new GraphicsPath();
            RectangleF rectf = new RectangleF(0, 0, this.Width, this.Height);
            path.AddEllipse(rectf);
            path.CloseFigure();
            this.Region = new Region(path);
            e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
            if (this._isKindsColor)
            {
              LinearGradientBrush brush = new LinearGradientBrush(e.ClipRectangle, this.BackColor, this._alternateColor, 90f);
              e.Graphics.FillEllipse(brush, e.ClipRectangle);
              brush.Dispose();// release resource
            }
            else
            {
              e.Graphics.FillPath(new SolidBrush(this.BackColor), path);
            }

            if (this._isBorderShow)
            {
              pen = new Pen(this._borderColor, this._borderWidth);
              rectf = new RectangleF((float)(this._borderWidth / 2.0), (float)((this._borderWidth) / 2.0), (float)(this.Width - this._borderWidth), (float)(this.Height - this._borderWidth));
              path = new GraphicsPath();

              path.AddEllipse(rectf);
              path.CloseFigure();
              e.Graphics.DrawPath(pen, path);
              pen.Dispose();
            }                      
            break;
        }
      }

      base.OnPaint(e);
    }
        //带弧线的方形边框
        private GraphicsPath GetRoundRectPath(RectangleF rect, int num,float offset)
        {
            GraphicsPath path = new GraphicsPath();
            RectangleF rect2 = new RectangleF(rect.Location, new Size(num, num));
            rect2.X += offset;
            rect2.Y =rect2.Top+offset;
            path.AddArc(rect2, 180f, 90f);//左上角
            rect2.X = rect.Right - num-offset;
            path.AddArc(rect2, 270f, 90f);//右上角
            rect2.Y = rect.Bottom -num-offset;
            path.AddArc(rect2, 0f, 90f);//右下角
            rect2.X = rect.Left+offset;
            path.AddArc(rect2, 90f, 90f);//左下角
            path.CloseFigure();
            return path;
        }

        protected override void WndProc(ref Message m)
        {
            if (m.Msg != 20)
            {
                base.WndProc(ref m);
            }
        }
    }
}

上面就是我显示的全部代码,实现效果就是图中所示。另外这个是最简单的一个自定义控件的实现,没有涉及事件,这个可以作为其他控件的基类,如按钮,标签等等。后面的文章我会对其他常用控件进行重绘。敬请期待,当然,如果大家有一些好的实现方式,也可以留言告诉我,大家共同学习进步。

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表