前提
入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章。
开源地址:https://gitee.com/kwwwvagaa/net_winform_custom_control
如果觉得写的还行,请点个 star 支持一下吧
目录
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 }
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 }
用处及效果
最后的话
如果你喜欢的话,请到 https://gitee.com/kwwwvagaa/net_winform_custom_control 点个星 星吧