前提

入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章。

开源地址:https://gitee.com/kwwwvagaa/net_winform_custom_control
<https://gitee.com/kwwwvagaa/net_winform_custom_control>

如果觉得写的还行,请点个 star 支持一下吧

欢迎前来交流探讨: 企鹅群568015492  <https://shang.qq.com/wpa/qunwpa?
idkey=6e08741ef16fe53bf0314c1c9e336c4f626047943a8b76bac062361bab6b4f8d>

目录

https://www.cnblogs.com/bfyx/p/11364884.html
<https://www.cnblogs.com/bfyx/p/11364884.html>

准备工作

也没什么可准备的了

开始

添加一个用户控件,命名UCStep

来点属性
1 public event EventHandler IndexChecked; 2 3 private Color m_stepBackColor
= Color.FromArgb(100, 100, 100); 4 /// <summary> 5 /// 步骤背景色 6 /// </summary>
7 [Description("步骤背景色"), Category("自定义")] 8 public Color StepBackColor 9 {
10 get { return m_stepBackColor; } 11 set { m_stepBackColor = value; } 12 } 13
14 private Color m_stepForeColor = Color.FromArgb(255, 85, 51); 15 /// <summary>
16 /// 步骤前景色 17 /// </summary> 18 [Description("步骤前景色"), Category("自定义")] 19
public Color StepForeColor 20 { 21 get { return m_stepForeColor; } 22 set {
m_stepForeColor = value; } 23 } 24 25 private Color m_stepFontColor =
Color.White;26 /// <summary> 27 /// 步骤文字颜色 28 /// </summary> 29 [Description("
步骤文字景色"), Category("自定义")] 30 public Color StepFontColor 31 { 32 get { return
m_stepFontColor; }33 set { m_stepFontColor = value; } 34 } 35 36 private int
m_stepWidth =35; 37 /// <summary> 38 /// 步骤宽度 39 /// </summary> 40 [Description(
"步骤宽度景色"), Category("自定义")] 41 public int StepWidth 42 { 43 get { return
m_stepWidth; }44 set { m_stepWidth = value; } 45 } 46 47 private string[]
m_steps =new string[] { "step1", "step2", "step3" }; 48 49 [Description("步骤"),
Category("自定义")] 50 public string[] Steps 51 { 52 get { return m_steps; } 53
set 54 { 55 if (m_steps == null || m_steps.Length <= 1) 56 return; 57 m_steps =
value;58 Refresh(); 59 } 60 } 61 62 private int m_stepIndex = 0; 63 64
[Description("步骤位置"), Category("自定义")] 65 public int StepIndex 66 { 67 get {
return m_stepIndex; } 68 set 69 { 70 if (m_stepIndex >= Steps.Length) 71 return
;72 m_stepIndex = value; 73 Refresh(); 74 if (IndexChecked != null) 75 { 76
IndexChecked(this, null); 77 } 78 } 79 }
重绘
1 protected override void OnPaint(PaintEventArgs e) 2 { 3 base.OnPaint(e);
4 var g = e.Graphics; 5 g.SmoothingMode = SmoothingMode.AntiAlias; //
使绘图质量最高,即消除锯齿 6 g.InterpolationMode = InterpolationMode.HighQualityBicubic; 7
g.CompositingQuality = CompositingQuality.HighQuality; 8 9 if (m_steps != null
&& m_steps.Length >0) 10 { 11 System.Drawing.SizeF sizeFirst =
g.MeasureString(m_steps[0], this.Font); 12 int y = (this.Height - m_stepWidth -
10 - (int)sizeFirst.Height) / 2; 13 if (y < 0) 14 y = 0; 15 16 int intTxtY = y
+ m_stepWidth +10; 17 int intLeft = 0; 18 if (sizeFirst.Width > m_stepWidth) 19
{20 intLeft = (int)(sizeFirst.Width - m_stepWidth) / 2 + 1; 21 } 22 23 int
intRight =0; 24 System.Drawing.SizeF sizeEnd =
g.MeasureString(m_steps[m_steps.Length -1], this.Font); 25 if (sizeEnd.Width >
m_stepWidth)26 { 27 intRight = (int)(sizeEnd.Width - m_stepWidth) / 2 + 1; 28
}29 30 int intSplitWidth = 20; 31 intSplitWidth = (this.Width - m_steps.Length
- (m_steps.Length * m_stepWidth) - intRight) / (m_steps.Length -1); 32 if
(intSplitWidth <20) 33 intSplitWidth = 20; 34 35 for (int i = 0; i <
m_steps.Length; i++) 36 { 37 #region 画圆,横线 38 g.FillEllipse(new
SolidBrush(m_stepBackColor),new Rectangle(new Point(intLeft + i * (m_stepWidth
+ intSplitWidth), y),new Size(m_stepWidth, m_stepWidth))); 39 40 if
(m_stepIndex > i) 41 { 42 g.FillEllipse(new SolidBrush(m_stepForeColor), new
Rectangle(new Point(intLeft + i * (m_stepWidth + intSplitWidth) + 2, y + 2), new
Size(m_stepWidth -4, m_stepWidth - 4))); 43 44 if (i != m_steps.Length - 1) 45
{46 if (m_stepIndex == i + 1) 47 { 48 g.DrawLine(new Pen(m_stepForeColor, 2),
new Point(intLeft + i * (m_stepWidth + intSplitWidth) + m_stepWidth, y +
(m_stepWidth /2)), new Point((i + 1) * (m_stepWidth + intSplitWidth) -
intSplitWidth /2, y + (m_stepWidth / 2))); 49 g.DrawLine(new
Pen(m_stepBackColor,2), new Point(intLeft + i * (m_stepWidth + intSplitWidth) +
m_stepWidth + intSplitWidth /2, y + (m_stepWidth / 2)), new Point((i + 1) *
(m_stepWidth + intSplitWidth), y + (m_stepWidth /2))); 50 } 51 else 52 { 53
g.DrawLine(new Pen(m_stepForeColor, 2), new Point(intLeft + i * (m_stepWidth +
intSplitWidth) + m_stepWidth, y + (m_stepWidth /2)), new Point((i + 1) *
(m_stepWidth + intSplitWidth), y + (m_stepWidth /2))); 54 } 55 } 56 } 57 else
58 { 59 if (i != m_steps.Length - 1) 60 { 61 g.DrawLine(new
Pen(m_stepBackColor,2), new Point(intLeft + i * (m_stepWidth + intSplitWidth) +
m_stepWidth, y + (m_stepWidth /2)), new Point((i + 1) * (m_stepWidth +
intSplitWidth), y + (m_stepWidth /2))); 62 } 63 } 64 65 System.Drawing.SizeF
_numSize = g.MeasureString((i +1).ToString(), this.Font); 66 g.DrawString((i + 1
).ToString(), Font,new SolidBrush(m_stepFontColor), new Point(intLeft + i *
(m_stepWidth + intSplitWidth) + (m_stepWidth - (int)_numSize.Width) / 2 + 1, y
+ (m_stepWidth - (int)_numSize.Height) / 2 + 1)); 67 #endregion 68 69
System.Drawing.SizeF sizeTxt = g.MeasureString(m_steps[i],this.Font); 70
g.DrawString(m_steps[i], Font,new SolidBrush(m_stepIndex > i ? m_stepForeColor
: m_stepBackColor),new Point(intLeft + i * (m_stepWidth + intSplitWidth) +
(m_stepWidth - (int)sizeTxt.Width) / 2 + 1, intTxtY)); 71 } 72 } 73 74 }
全部代码
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 UCStep : UserControl 14 { 15 16 [Description("步骤更改事件"
), Category("自定义")] 17 public event EventHandler IndexChecked; 18 19 private
Color m_stepBackColor = Color.FromArgb(100, 100, 100); 20 /// <summary> 21 ///
步骤背景色 22 /// </summary> 23 [Description("步骤背景色"), Category("自定义")] 24 public
Color StepBackColor 25 { 26 get { return m_stepBackColor; } 27 set {
m_stepBackColor = value; } 28 } 29 30 private Color m_stepForeColor =
Color.FromArgb(255, 85, 51); 31 /// <summary> 32 /// 步骤前景色 33 /// </summary>
34 [Description("步骤前景色"), Category("自定义")] 35 public Color StepForeColor 36
{ 37 get { return m_stepForeColor; } 38 set { m_stepForeColor = value; } 39 }
40 41 private Color m_stepFontColor = Color.White; 42 /// <summary> 43 ///
步骤文字颜色 44 /// </summary> 45 [Description("步骤文字景色"), Category("自定义")] 46 public
Color StepFontColor 47 { 48 get { return m_stepFontColor; } 49 set {
m_stepFontColor = value; } 50 } 51 52 private int m_stepWidth = 35; 53 ///
<summary> 54 /// 步骤宽度 55 /// </summary> 56 [Description("步骤宽度景色"), Category("
自定义")] 57 public int StepWidth 58 { 59 get { return m_stepWidth; } 60 set
{ m_stepWidth = value; } 61 } 62 63 private string[] m_steps = new string[]
{"step1", "step2", "step3" }; 64 65 [Description("步骤"), Category("自定义")] 66
public string[] Steps 67 { 68 get { return m_steps; } 69 set 70 { 71 if
(m_steps ==null || m_steps.Length <= 1) 72 return; 73 m_steps = value; 74
Refresh(); 75 } 76 } 77 78 private int m_stepIndex = 0; 79 80
[Description("步骤位置"), Category("自定义")] 81 public int StepIndex 82 { 83 get {
return m_stepIndex; } 84 set 85 { 86 if (m_stepIndex >= Steps.Length) 87
return; 88 m_stepIndex = value; 89 Refresh(); 90 if (IndexChecked != null)
91 { 92 IndexChecked(this, null); 93 } 94 } 95 } 96 97 public UCStep()
98 { 99 InitializeComponent(); 100 this
.SetStyle(ControlStyles.AllPaintingInWmPaint,true); 101 this
.SetStyle(ControlStyles.DoubleBuffer,true); 102 this
.SetStyle(ControlStyles.ResizeRedraw,true); 103 this
.SetStyle(ControlStyles.Selectable,true); 104 this
.SetStyle(ControlStyles.SupportsTransparentBackColor,true); 105 this
.SetStyle(ControlStyles.UserPaint,true); 106 } 107 108 protected override void
OnPaint(PaintEventArgs e)109 { 110 base.OnPaint(e); 111 var g = e.Graphics; 112
g.SmoothingMode = SmoothingMode.AntiAlias;//使绘图质量最高,即消除锯齿 113
g.InterpolationMode = InterpolationMode.HighQualityBicubic; 114
g.CompositingQuality = CompositingQuality.HighQuality; 115 116 if (m_steps !=
null && m_steps.Length > 0) 117 { 118 System.Drawing.SizeF sizeFirst =
g.MeasureString(m_steps[0], this.Font); 119 int y = (this.Height - m_stepWidth -
10 - (int)sizeFirst.Height) / 2; 120 if (y < 0) 121 y = 0; 122 123 int intTxtY
= y + m_stepWidth +10; 124 int intLeft = 0; 125 if (sizeFirst.Width >
m_stepWidth)126 { 127 intLeft = (int)(sizeFirst.Width - m_stepWidth) / 2 + 1;
128 } 129 130 int intRight = 0; 131 System.Drawing.SizeF sizeEnd =
g.MeasureString(m_steps[m_steps.Length -1], this.Font); 132 if (sizeEnd.Width >
m_stepWidth)133 { 134 intRight = (int)(sizeEnd.Width - m_stepWidth) / 2 + 1;
135 } 136 137 int intSplitWidth = 20; 138 intSplitWidth = (this.Width -
m_steps.Length - (m_steps.Length * m_stepWidth) - intRight) / (m_steps.Length -1
);139 if (intSplitWidth < 20) 140 intSplitWidth = 20; 141 142 for (int i = 0; i
< m_steps.Length; i++) 143 { 144 #region 画圆,横线 145 g.FillEllipse(new
SolidBrush(m_stepBackColor),new Rectangle(new Point(intLeft + i * (m_stepWidth
+ intSplitWidth), y),new Size(m_stepWidth, m_stepWidth))); 146 147 if
(m_stepIndex > i) 148 { 149 g.FillEllipse(new SolidBrush(m_stepForeColor), new
Rectangle(new Point(intLeft + i * (m_stepWidth + intSplitWidth) + 2, y + 2), new
Size(m_stepWidth -4, m_stepWidth - 4))); 150 151 if (i != m_steps.Length - 1)
152 { 153 if (m_stepIndex == i + 1) 154 { 155 g.DrawLine(new
Pen(m_stepForeColor,2), new Point(intLeft + i * (m_stepWidth + intSplitWidth) +
m_stepWidth, y + (m_stepWidth /2)), new Point((i + 1) * (m_stepWidth +
intSplitWidth) - intSplitWidth /2, y + (m_stepWidth / 2))); 156 g.DrawLine(new
Pen(m_stepBackColor,2), new Point(intLeft + i * (m_stepWidth + intSplitWidth) +
m_stepWidth + intSplitWidth /2, y + (m_stepWidth / 2)), new Point((i + 1) *
(m_stepWidth + intSplitWidth), y + (m_stepWidth /2))); 157 } 158 else 159 {
160 g.DrawLine(new Pen(m_stepForeColor, 2), new Point(intLeft + i *
(m_stepWidth + intSplitWidth) + m_stepWidth, y + (m_stepWidth /2)), new
Point((i +1) * (m_stepWidth + intSplitWidth), y + (m_stepWidth / 2))); 161 }
162 } 163 } 164 else 165 { 166 if (i != m_steps.Length - 1) 167 { 168
g.DrawLine(new Pen(m_stepBackColor, 2), new Point(intLeft + i * (m_stepWidth +
intSplitWidth) + m_stepWidth, y + (m_stepWidth /2)), new Point((i + 1) *
(m_stepWidth + intSplitWidth), y + (m_stepWidth /2))); 169 } 170 } 171 172
System.Drawing.SizeF _numSize = g.MeasureString((i +1).ToString(), this.Font);
173 g.DrawString((i + 1).ToString(), Font, new SolidBrush(m_stepFontColor), new
Point(intLeft + i * (m_stepWidth + intSplitWidth) + (m_stepWidth - (int
)_numSize.Width) /2 + 1, y + (m_stepWidth - (int)_numSize.Height) / 2 + 1)); 174
#endregion 175 176 System.Drawing.SizeF sizeTxt = g.MeasureString(m_steps[i],
this.Font); 177 g.DrawString(m_steps[i], Font, new SolidBrush(m_stepIndex > i ?
m_stepForeColor : m_stepBackColor),new Point(intLeft + i * (m_stepWidth +
intSplitWidth) + (m_stepWidth - (int)sizeTxt.Width) / 2 + 1, intTxtY)); 178 }
179 } 180 181 } 182 } 183 } View Code 1 namespace HZH_Controls.Controls 2 {
3 partial class UCStep 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
.SuspendLayout();32 // 33 // UCStep 34 // 35 this.AutoScaleMode =
System.Windows.Forms.AutoScaleMode.None;36 this.BackColor =
System.Drawing.Color.Transparent;37 this.Name = "UCStep"; 38 this.Size = new
System.Drawing.Size(239, 80); 39 this.ResumeLayout(false); 40 41 } 42 43
#endregion 44 } 45 } View Code
用处及效果



最后的话

如果你喜欢的话,请到 https://gitee.com/kwwwvagaa/net_winform_custom_control
<https://gitee.com/kwwwvagaa/net_winform_custom_control> 点个星 星吧