前提
入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章。
GitHub:https://github.com/kwwwvagaa/NetWinformControl 
<https://github.com/kwwwvagaa/NetWinformControl>
码云:https://gitee.com/kwwwvagaa/net_winform_custom_control.git 
<https://gitee.com/kwwwvagaa/net_winform_custom_control.git>
如果觉得写的还行,请点个 star 支持一下吧
欢迎前来交流探讨: 企鹅群568015492  
<https://shang.qq.com/wpa/qunwpa?idkey=6e08741ef16fe53bf0314c1c9e336c4f626047943a8b76bac062361bab6b4f8d>
麻烦博客下方点个【推荐】,谢谢
NuGet
Install-Package HZH_Controls 
目录
https://www.cnblogs.com/bfyx/p/11364884.html 
<https://www.cnblogs.com/bfyx/p/11364884.html>
用处及效果
准备工作
这个用到GDI+画的,请先了解一下GDI+
还有用到了基类控件UCControlBase来控制圆角和背景色,如果还不了解请移步查看
(一)c#Winform自定义控件-基类控件 <https://www.cnblogs.com/bfyx/p/11361809.html>
另外用到了水波控件UCWave,如果不了解请移步查看
(四十四)c#Winform自定义控件-水波 <https://www.cnblogs.com/bfyx/p/11397975.html>
开始
添加一个用户控件UCProcessWave,继承UCControlBase
一些属性
 1 private bool m_isRectangle = false;  2 [Description("是否矩形"), Category("自定义"
)] 3 public bool IsRectangle  4  {  5 get { return m_isRectangle; }  6 set  7  {
 8 m_isRectangle = value;  9 if (value)  10  {  11 base.ConerRadius = 10;  12  }
 13 else  14  {  15 base.ConerRadius = Math.Min(this.Width, this.Height);  16  }
 17  }  18  }  19 #region 不再使用的父类属性 English:Parent class attributes that are no 
longer used 20 [Browsable(false)]  21 public new int ConerRadius  22  {  23 get;
 24 set;  25  }  26 [Browsable(false)]  27 public new bool IsRadius  28  {  29 
get;  30 set;  31  }  32  33 [Browsable(false)]  34 public new Color FillColor  
35  {  36 get;  37 set;  38  }  39 #endregion  40  41  42 [Description("值变更事件"
), Category("自定义")]  43 public event EventHandler ValueChanged;  44 int m_value 
=0;  45 [Description("当前属性"), Category("自定义")]  46 public int Value  47  {  48 
set  49  {  50 if (value > m_maxValue)  51 m_value = m_maxValue;  52 else if 
(value <0)  53 m_value = 0;  54 else  55 m_value = value;  56 if (ValueChanged 
!=null)  57 ValueChanged(this, null);  58 ucWave1.Height = (int)((double
)m_value / (double)m_maxValue * this.Height) + ucWave1.WaveHeight;  59  
Refresh(); 60  }  61 get  62  {  63 return m_value;  64  }  65  }  66  67 
private int m_maxValue = 100;  68  69 [Description("最大值"), Category("自定义")]  70 
public int MaxValue  71  {  72 get { return m_maxValue; }  73 set  74  {  75 if 
(value < m_value)  76 m_maxValue = m_value;  77 else  78 m_maxValue = value;  79
 Refresh(); 80  }  81  }  82  83 public override Font Font  84  {  85 get  86  {
 87 return base.Font;  88  }  89 set  90  {  91 base.Font = value;  92  }  93  }
 94  95 public override Color ForeColor  96  {  97 get  98  {  99 return base
.ForeColor;100  } 101 set 102  { 103 base.ForeColor = value; 104  } 105  } 106 
107 [Description("值颜色"), Category("自定义")] 108 public Color ValueColor 109  { 110
get { return this.ucWave1.WaveColor; } 111 set 112  { 113 this
.ucWave1.WaveColor = value; 114  } 115  } 116 117 [Description("边框宽度"), 
Category("自定义")] 118 public override int RectWidth 119  { 120 get 121  { 122 
return base.RectWidth; 123  } 124 set 125  { 126 if (value < 4) 127 base
.RectWidth =4; 128 else 129 base.RectWidth = value; 130  } 131 } 
构造函数一些设置
 1 public UCProcessWave()  2  {  3  InitializeComponent();  4 this
.SetStyle(ControlStyles.AllPaintingInWmPaint,true);  5 this
.SetStyle(ControlStyles.DoubleBuffer,true);  6 this
.SetStyle(ControlStyles.ResizeRedraw,true);  7 this
.SetStyle(ControlStyles.Selectable,true);  8 this
.SetStyle(ControlStyles.SupportsTransparentBackColor,true);  9 this
.SetStyle(ControlStyles.UserPaint,true); 10 base.IsRadius = true; 11 base
.IsShowRect =false; 12 RectWidth = 4; 13 RectColor = Color.White; 14 
ucWave1.Height = (int)((double)m_value / (double)m_maxValue * this.Height) + 
ucWave1.WaveHeight;15 this.SizeChanged += UCProcessWave_SizeChanged; 16 this
.ucWave1.OnPainted += ucWave1_Painted; 17 base.ConerRadius = Math.Min(this
.Width,this.Height); 18 } 
重绘
 1 protected override void OnPaint(PaintEventArgs e)  2  {  3 base.OnPaint(e); 
 4  e.Graphics.SetGDIHigh();  5 if (!m_isRectangle)  6  {  7 //
这里曲线救国,因为设置了控件区域导致的毛边,通过画一个没有毛边的圆遮挡  8 SolidBrush solidBrush = new 
SolidBrush(Color.White); 9 e.Graphics.DrawEllipse(new Pen(solidBrush, 2), new 
Rectangle(-1, -1, this.Width + 2, this.Height + 2)); 10  } 11 string strValue = 
((double)m_value / (double)m_maxValue).ToString("0.%"); 12 System.Drawing.SizeF 
sizeF = e.Graphics.MeasureString(strValue, Font); 13 
e.Graphics.DrawString(strValue, Font,new SolidBrush(ForeColor), new PointF((this
.Width - sizeF.Width) /2, (this.Height - sizeF.Height) / 2 + 1)); 14 } 
波形控件重绘时处理
 1 void ucWave1_Painted(object sender, PaintEventArgs e)  2  {  3  
e.Graphics.SetGDIHigh(); 4 if (IsShowRect)  5  {  6 if (m_isRectangle)  7  {  8 
Color rectColor = RectColor;  9 Pen pen = new Pen(rectColor, (float)RectWidth); 
10 Rectangle clientRectangle = new Rectangle(0, this.ucWave1.Height - this
.Height,this.Width, this.Height); 11 GraphicsPath graphicsPath = new 
GraphicsPath();12 graphicsPath.AddArc(clientRectangle.X, clientRectangle.Y, 10, 
10, 180f, 90f); 13 graphicsPath.AddArc(clientRectangle.Width - 10 - 1, 
clientRectangle.Y,10, 10, 270f, 90f); 14 
graphicsPath.AddArc(clientRectangle.Width -10 - 1, clientRectangle.Bottom - 10 -
1, 10, 10, 0f, 90f); 15 graphicsPath.AddArc(clientRectangle.X, 
clientRectangle.Bottom -10 - 1, 10, 10, 90f, 90f); 16  
graphicsPath.CloseFigure();17  e.Graphics.DrawPath(pen, graphicsPath); 18  } 19 
else 20  { 21 SolidBrush solidBrush = new SolidBrush(RectColor); 22 
e.Graphics.DrawEllipse(new Pen(solidBrush, RectWidth), new Rectangle(0, this
.ucWave1.Height -this.Height, this.Width, this.Height)); 23  } 24  } 25 26 if (!
m_isRectangle)27  { 28 //这里曲线救国,因为设置了控件区域导致的毛边,通过画一个没有毛边的圆遮挡 29 SolidBrush 
solidBrush1 =new SolidBrush(Color.White); 30 e.Graphics.DrawEllipse(new 
Pen(solidBrush1,2), new Rectangle(-1, this.ucWave1.Height - this.Height - 1, 
this.Width + 2, this.Height + 2)); 31  } 32 string strValue = ((double)m_value 
/ (double)m_maxValue).ToString("0.%"); 33 System.Drawing.SizeF sizeF = 
e.Graphics.MeasureString(strValue, Font);34 e.Graphics.DrawString(strValue, 
Font,new SolidBrush(ForeColor), new PointF((this.Width - sizeF.Width) / 2, (this
.ucWave1.Height -this.Height) + (this.Height - sizeF.Height) / 2)); 35 } 
不知道你们有没有注意这句话
//这里曲线救国,因为设置了控件区域导致的毛边,通过画一个没有毛边的圆遮挡 
因为设置原价导致了区域毛边,所有画个没有毛边的边框覆盖之
 
完整代码
 1 using System;  2 using System.Collections.Generic;  3 using 
System.ComponentModel; 4 using System.Drawing;  5 using System.Data;  6 using 
System.Linq; 7 using System.Text;  8 using System.Windows.Forms;  9 using 
System.Drawing.Drawing2D; 10  11 namespace HZH_Controls.Controls  12 {  13 
public partial class UCProcessWave : UCControlBase  14  {  15 private bool 
m_isRectangle =false;  16 [Description("是否矩形"), Category("自定义")]  17 public bool
 IsRectangle 18  {  19 get { return m_isRectangle; }  20 set  21  {  22 
m_isRectangle = value;  23 if (value)  24  {  25 base.ConerRadius = 10;  26  }  
27 else  28  {  29 base.ConerRadius = Math.Min(this.Width, this.Height);  30  } 
 31  }  32  }  33 #region 不再使用的父类属性 English:Parent class attributes that are no 
longer used 34 [Browsable(false)]  35 public new int ConerRadius  36  {  37 get;
 38 set;  39  }  40 [Browsable(false)]  41 public new bool IsRadius  42  {  43 
get;  44 set;  45  }  46  47 [Browsable(false)]  48 public new Color FillColor  
49  {  50 get;  51 set;  52  }  53 #endregion  54  55  56 [Description("值变更事件"
), Category("自定义")]  57 public event EventHandler ValueChanged;  58 int m_value 
=0;  59 [Description("当前属性"), Category("自定义")]  60 public int Value  61  {  62 
set  63  {  64 if (value > m_maxValue)  65 m_value = m_maxValue;  66 else if 
(value <0)  67 m_value = 0;  68 else  69 m_value = value;  70 if (ValueChanged 
!=null)  71 ValueChanged(this, null);  72 ucWave1.Height = (int)((double
)m_value / (double)m_maxValue * this.Height) + ucWave1.WaveHeight;  73  
Refresh(); 74  }  75 get  76  {  77 return m_value;  78  }  79  }  80  81 
private int m_maxValue = 100;  82  83 [Description("最大值"), Category("自定义")]  84 
public int MaxValue  85  {  86 get { return m_maxValue; }  87 set  88  {  89 if 
(value < m_value)  90 m_maxValue = m_value;  91 else  92 m_maxValue = value;  93
 Refresh(); 94  }  95  }  96  97 public override Font Font  98  {  99 get 100  {
101 return base.Font; 102  } 103 set 104  { 105 base.Font = value; 106  } 107  }
108 109 public override Color ForeColor 110  { 111 get 112  { 113 return base
.ForeColor;114  } 115 set 116  { 117 base.ForeColor = value; 118  } 119  } 120 
121 [Description("值颜色"), Category("自定义")] 122 public Color ValueColor 123  { 124
get { return this.ucWave1.WaveColor; } 125 set 126  { 127 this
.ucWave1.WaveColor = value; 128  } 129  } 130 131 [Description("边框宽度"), 
Category("自定义")] 132 public override int RectWidth 133  { 134 get 135  { 136 
return base.RectWidth; 137  } 138 set 139  { 140 if (value < 4) 141 base
.RectWidth =4; 142 else 143 base.RectWidth = value; 144  } 145  } 146 147 public
 UCProcessWave()148  { 149  InitializeComponent(); 150 this
.SetStyle(ControlStyles.AllPaintingInWmPaint,true); 151 this
.SetStyle(ControlStyles.DoubleBuffer,true); 152 this
.SetStyle(ControlStyles.ResizeRedraw,true); 153 this
.SetStyle(ControlStyles.Selectable,true); 154 this
.SetStyle(ControlStyles.SupportsTransparentBackColor,true); 155 this
.SetStyle(ControlStyles.UserPaint,true); 156 base.IsRadius = true; 157 base
.IsShowRect =false; 158 RectWidth = 4; 159 RectColor = Color.White; 160 
ucWave1.Height = (int)((double)m_value / (double)m_maxValue * this.Height) + 
ucWave1.WaveHeight;161 this.SizeChanged += UCProcessWave_SizeChanged; 162 this
.ucWave1.OnPainted += ucWave1_Painted; 163 base.ConerRadius = Math.Min(this
.Width,this.Height); 164  } 165 166 void ucWave1_Painted(object sender, 
PaintEventArgs e)167  { 168  e.Graphics.SetGDIHigh(); 169 if (IsShowRect) 170  {
171 if (m_isRectangle) 172  { 173 Color rectColor = RectColor; 174 Pen pen = new
 Pen(rectColor, (float)RectWidth); 175 Rectangle clientRectangle = new 
Rectangle(0, this.ucWave1.Height - this.Height, this.Width, this.Height); 176 
GraphicsPath graphicsPath =new GraphicsPath(); 177 
graphicsPath.AddArc(clientRectangle.X, clientRectangle.Y,10, 10, 180f, 90f); 178
 graphicsPath.AddArc(clientRectangle.Width -10 - 1, clientRectangle.Y, 10, 10, 
270f, 90f);179 graphicsPath.AddArc(clientRectangle.Width - 10 - 1, 
clientRectangle.Bottom -10 - 1, 10, 10, 0f, 90f); 180 
graphicsPath.AddArc(clientRectangle.X, clientRectangle.Bottom -10 - 1, 10, 10, 
90f, 90f);181  graphicsPath.CloseFigure(); 182  e.Graphics.DrawPath(pen, 
graphicsPath);183  } 184 else 185  { 186 SolidBrush solidBrush = new 
SolidBrush(RectColor);187 e.Graphics.DrawEllipse(new Pen(solidBrush, RectWidth),
new Rectangle(0, this.ucWave1.Height - this.Height, this.Width, this.Height)); 
188  } 189  } 190 191 if (!m_isRectangle) 192  { 193 //
这里曲线救国,因为设置了控件区域导致的毛边,通过画一个没有毛边的圆遮挡 194 SolidBrush solidBrush1 = new 
SolidBrush(Color.White);195 e.Graphics.DrawEllipse(new Pen(solidBrush1, 2), new 
Rectangle(-1, this.ucWave1.Height - this.Height - 1, this.Width + 2, this
.Height +2)); 196  } 197 string strValue = ((double)m_value / (double
)m_maxValue).ToString("0.%"); 198 System.Drawing.SizeF sizeF = 
e.Graphics.MeasureString(strValue, Font);199 e.Graphics.DrawString(strValue, 
Font,new SolidBrush(ForeColor), new PointF((this.Width - sizeF.Width) / 2, (this
.ucWave1.Height -this.Height) + (this.Height - sizeF.Height) / 2)); 200  } 201 
202 void UCProcessWave_SizeChanged(object sender, EventArgs e) 203  { 204 if (!
m_isRectangle)205  { 206 base.ConerRadius = Math.Min(this.Width, this.Height); 
207 if (this.Width != this.Height) 208  { 209 this.Size = new Size(Math.Min(this
.Width,this.Height), Math.Min(this.Width, this.Height)); 210  } 211  } 212  } 
213 214 protected override void OnPaint(PaintEventArgs e) 215  { 216 base
.OnPaint(e);217  e.Graphics.SetGDIHigh(); 218 if (!m_isRectangle) 219  { 220 //
这里曲线救国,因为设置了控件区域导致的毛边,通过画一个没有毛边的圆遮挡 221 SolidBrush solidBrush = new 
SolidBrush(Color.White);222 e.Graphics.DrawEllipse(new Pen(solidBrush, 2), new 
Rectangle(-1, -1, this.Width + 2, this.Height + 2)); 223  } 224 string strValue 
= ((double)m_value / (double)m_maxValue).ToString("0.%"); 225 
System.Drawing.SizeF sizeF = e.Graphics.MeasureString(strValue, Font); 226 
e.Graphics.DrawString(strValue, Font,new SolidBrush(ForeColor), new PointF((this
.Width - sizeF.Width) /2, (this.Height - sizeF.Height) / 2 + 1)); 227  } 228  } 
229 } View Code  1 namespace HZH_Controls.Controls  2 {  3 partial class 
UCProcessWave 4  {  5 /// <summary>  6 /// 必需的设计器变量。  7 /// </summary>  8 
private System.ComponentModel.IContainer components = null;  9 10 /// <summary> 
11 /// 清理所有正在使用的资源。 12 /// </summary> 13 /// <param name="disposing">
如果应释放托管资源,为 true;否则为 false。</param> 14 protected override void Dispose(bool 
disposing)15  { 16 if (disposing && (components != null)) 17  { 18  
components.Dispose();19  } 20 base.Dispose(disposing); 21  } 22 23 #region 
组件设计器生成的代码24 25 /// <summary> 26 /// 设计器支持所需的方法 - 不要 27 /// 使用代码编辑器修改此方法的内容。 28 
/// </summary> 29 private void InitializeComponent() 30  { 31 this.ucWave1 = new
 HZH_Controls.Controls.UCWave();32 this.SuspendLayout(); 33 // 34 // ucWave1 35 
// 36 this.ucWave1.Dock = System.Windows.Forms.DockStyle.Bottom; 37 this
.ucWave1.Location =new System.Drawing.Point(0, 140); 38 this.ucWave1.Name = "
ucWave1"; 39 this.ucWave1.Size = new System.Drawing.Size(150, 10); 40 this
.ucWave1.TabIndex =0; 41 this.ucWave1.Text = "ucWave1"; 42 this
.ucWave1.WaveColor = System.Drawing.Color.FromArgb(((int)(((byte)(73)))), ((int
)(((byte)(119)))), ((int)(((byte)(232))))); 43 this.ucWave1.WaveHeight = 15; 44 
this.ucWave1.WaveSleep = 100; 45 this.ucWave1.WaveWidth = 100; 46 // 47 // 
UCProcessWave48 // 49 this.AutoScaleMode = 
System.Windows.Forms.AutoScaleMode.None;50 this.BackColor = 
System.Drawing.Color.FromArgb(((int)(((byte)(197)))), ((int)(((byte)(229)))), ((
int)(((byte)(250))))); 51 this.Controls.Add(this.ucWave1); 52 this.Name = "
UCProcessWave"; 53 this.Size = new System.Drawing.Size(150, 150); 54 this
.ResumeLayout(false); 55 56  } 57 58 #endregion 59 60 private UCWave ucWave1; 61
 }62 } View Code 
 
最后的话
如果你喜欢的话,请到 https://gitee.com/kwwwvagaa/net_winform_custom_control 
<https://gitee.com/kwwwvagaa/net_winform_custom_control> 点个星星吧
热门工具 换一换