前提
入行已经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>
准备工作
终于到文本框了,文本框将包含原文本框扩展,透明文本框,数字输入文本框,带边框文本框
本文将讲解原文本框扩展,主要增加水印和输入控制
开始
添加一个组件,命名TextBoxEx,继承TextBox
属性
 1 private bool blnFocus = false;  2  3 private string _promptText = string
.Empty; 4  5 private Font _promptFont = new Font("微软雅黑", 15f, 
FontStyle.Regular, GraphicsUnit.Pixel); 6  7 private Color _promptColor = 
Color.Gray; 8  9 private Rectangle _myRectangle = Rectangle.FromLTRB(1, 3, 1000,
3);  10  11 private TextInputType _inputType = TextInputType.NotControl;  12  13
private string _regexPattern = "";  14  15 private string m_strOldValue = string
.Empty; 16  17 private decimal _maxValue = 1000000m;  18  19 private decimal 
_minValue = -1000000m;  20  21 private int _decLength = 2;  22  23 /// <summary>
 24 /// 水印文字  25 /// </summary>  26 [Description("水印文字"), Category("自定义")]  27 
public string PromptText  28  {  29 get  30  {  31 return this._promptText;  32 
 } 33 set  34  {  35 this._promptText = value;  36 this.OnPaint(null);  37  }  
38  }  39  40 [Description("水印字体"), Category("自定义")]  41 public Font PromptFont 
 42  {  43 get  44  {  45 return this._promptFont;  46  }  47 set  48  {  49 
this._promptFont = value;  50  }  51  }  52  53 [Description("水印颜色"), Category("
自定义")]  54 public Color PromptColor  55  {  56 get  57  {  58 return this
._promptColor; 59  }  60 set  61  {  62 this._promptColor = value;  63  }  64  }
 65  66 public Rectangle MyRectangle  67  {  68 get;  69 set;  70  }  71  72 
public string OldText  73  {  74 get;  75 set;  76  }  77  78 [Description("
获取或设置一个值,该值指示文本框中的文本输入类型。")]  79 public TextInputType InputType  80  {  81 get  
82  {  83 return this._inputType;  84  }  85 set  86  {  87 this._inputType = 
value; 88 if (value != TextInputType.NotControl)  89  {  90 TextChanged -= new 
EventHandler(this.TextBoxEx_TextChanged);  91 TextChanged += new EventHandler(
this.TextBoxEx_TextChanged);  92  }  93 else  94  {  95 TextChanged -= new 
EventHandler(this.TextBoxEx_TextChanged);  96  }  97  }  98  }  99 /// <summary>
100 /// 获取或设置一个值,该值指示当输入类型InputType=Regex时,使用的正则表达式。 101 /// </summary> 102 
[Description("获取或设置一个值,该值指示当输入类型InputType=Regex时,使用的正则表达式。")] 103 public string 
RegexPattern104  { 105 get 106  { 107 return this._regexPattern; 108  } 109 set 
110  { 111 this._regexPattern = value; 112  } 113  } 114 /// <summary> 115 /// 
当InputType为数字类型时,能输入的最大值116 /// </summary> 117 [Description("
当InputType为数字类型时,能输入的最大值。")] 118 public decimal MaxValue 119  { 120 get 121  { 
122 return this._maxValue; 123  } 124 set 125  { 126 this._maxValue = value; 127
 }128  } 129 /// <summary> 130 /// 当InputType为数字类型时,能输入的最小值 131 /// </summary> 
132 [Description("当InputType为数字类型时,能输入的最小值。")] 133 public decimal MinValue 134  
{135 get 136  { 137 return this._minValue; 138  } 139 set 140  { 141 this
._minValue = value; 142  } 143  } 144 /// <summary> 145 /// 
当InputType为数字类型时,能输入的最小值146 /// </summary> 147 [Description("
当InputType为数字类型时,小数位数。")] 148 public int DecLength 149  { 150 get 151  { 152 
return this._decLength; 153  } 154 set 155  { 156 this._decLength = value; 157  
}158 } 
一些事件
 1 void TextBoxEx_KeyPress(object sender, KeyPressEventArgs e)  2  {  3 //以下代码 
取消按下回车或esc的“叮”声  4 if (e.KeyChar == System.Convert.ToChar(13) || e.KeyChar == 
System.Convert.ToChar(27))  5  {  6 e.Handled = true;  7  }  8  }  9 10 private 
void TextBoxEx_MouseUp(object sender, MouseEventArgs e) 11  { 12 if (this
.blnFocus)13  { 14 base.SelectAll(); 15 this.blnFocus = false; 16  } 17  } 18 19
private void TextBoxEx_GotFocus(object sender, EventArgs e) 20  { 21 this
.blnFocus =true; 22 base.SelectAll(); 23  } 24 25 private void 
TextBoxEx_TextChanged(object sender, EventArgs e) 26  { 27 if (this.Text == "") 
28  { 29 this.m_strOldValue = this.Text; 30  } 31 else if (this.m_strOldValue !=
this.Text) 32  { 33 if (!ControlHelper.CheckInputType(this.Text, this
._inputType,this._maxValue, this._minValue, this._decLength, this
._regexPattern))34  { 35 int num = base.SelectionStart; 36 if (this
.m_strOldValue.Length <this.Text.Length) 37  { 38 num--; 39  } 40 else 41  { 42 
num++; 43  } 44 base.TextChanged -= new EventHandler(this
.TextBoxEx_TextChanged);45 this.Text = this.m_strOldValue; 46 base.TextChanged 
+=new EventHandler(this.TextBoxEx_TextChanged); 47 if (num < 0) 48  { 49 num = 0
;50  } 51 base.SelectionStart = num; 52  } 53 else 54  { 55 this.m_strOldValue =
this.Text; 56  } 57  } 58 } 
重绘
 1 protected override void OnPaint(PaintEventArgs e)  2  {  3 base.OnPaint(e); 
 4 if (string.IsNullOrEmpty(this.Text) && !string.IsNullOrEmpty(this
._promptText)) 5  {  6 if (e == null)  7  {  8 using (Graphics graphics = 
Graphics.FromHwnd(base.Handle))  9  { 10 if (this.Text.Length == 0 && !string
.IsNullOrEmpty(this.PromptText)) 11  { 12 TextFormatFlags textFormatFlags = 
TextFormatFlags.EndEllipsis | TextFormatFlags.VerticalCenter; 13 if (this
.RightToLeft == RightToLeft.Yes) 14  { 15 textFormatFlags |= 
(TextFormatFlags.Right | TextFormatFlags.RightToLeft); 16  } 17 
TextRenderer.DrawText(graphics,this.PromptText, this._promptFont, base
.ClientRectangle,this._promptColor, textFormatFlags); 18  } 19  } 20  } 21  } 22
 } 
下面是完整代码
 1 // 版权所有 黄正辉 交流群:568015492 QQ:623128629  2 // 文件名称:TextBoxEx.cs  3 // 
创建日期:2019-08-15 16:03:44 4 // 功能描述:TextBox  5 // 项目地址:
https://gitee.com/kwwwvagaa/net_winform_custom_control  6 using System;  7 using
 System.Collections.Generic; 8 using System.ComponentModel;  9 using 
System.Diagnostics; 10 using System.Drawing;  11 using System.Linq;  12 using 
System.Text; 13 using System.Windows.Forms;  14  15 namespace 
HZH_Controls.Controls 16 {  17 public partial class TextBoxEx : TextBox  18  {  
19 private bool blnFocus = false;  20  21 private string _promptText = string
.Empty; 22  23 private Font _promptFont = new Font("微软雅黑", 15f, 
FontStyle.Regular, GraphicsUnit.Pixel); 24  25 private Color _promptColor = 
Color.Gray; 26  27 private Rectangle _myRectangle = Rectangle.FromLTRB(1, 3, 
1000, 3);  28  29 private TextInputType _inputType = TextInputType.NotControl;  
30  31 private string _regexPattern = "";  32  33 private string m_strOldValue =
string.Empty;  34  35 private decimal _maxValue = 1000000m;  36  37 private 
decimal _minValue = -1000000m;  38  39 private int _decLength = 2;  40  41 /// 
<summary>  42 /// 水印文字  43 /// </summary>  44 [Description("水印文字"), Category("
自定义")]  45 public string PromptText  46  {  47 get  48  {  49 return this
._promptText; 50  }  51 set  52  {  53 this._promptText = value;  54 this
.OnPaint(null);  55  }  56  }  57  58 [Description("水印字体"), Category("自定义")]  59
public Font PromptFont  60  {  61 get  62  {  63 return this._promptFont;  64  }
 65 set  66  {  67 this._promptFont = value;  68  }  69  }  70  71 [Description(
"水印颜色"), Category("自定义")]  72 public Color PromptColor  73  {  74 get  75  {  76
return this._promptColor;  77  }  78 set  79  {  80 this._promptColor = value;  
81  }  82  }  83  84 public Rectangle MyRectangle  85  {  86 get;  87 set;  88  
} 89  90 public string OldText  91  {  92 get;  93 set;  94  }  95  96 
[Description("获取或设置一个值,该值指示文本框中的文本输入类型。")]  97 public TextInputType InputType  
98  {  99 get 100  { 101 return this._inputType; 102  } 103 set 104  { 105 this
._inputType = value; 106 if (value != TextInputType.NotControl) 107  { 108 
TextChanged -=new EventHandler(this.TextBoxEx_TextChanged); 109 TextChanged += 
new EventHandler(this.TextBoxEx_TextChanged); 110  } 111 else 112  { 113 
TextChanged -=new EventHandler(this.TextBoxEx_TextChanged); 114  } 115  } 116  }
117 /// <summary> 118 /// 获取或设置一个值,该值指示当输入类型InputType=Regex时,使用的正则表达式。 119 /// 
</summary> 120 [Description("获取或设置一个值,该值指示当输入类型InputType=Regex时,使用的正则表达式。")] 121
public string RegexPattern 122  { 123 get 124  { 125 return this._regexPattern; 
126  } 127 set 128  { 129 this._regexPattern = value; 130  } 131  } 132 /// 
<summary> 133 /// 当InputType为数字类型时,能输入的最大值 134 /// </summary> 135 [Description("
当InputType为数字类型时,能输入的最大值。")] 136 public decimal MaxValue 137  { 138 get 139  { 
140 return this._maxValue; 141  } 142 set 143  { 144 this._maxValue = value; 145
 }146  } 147 /// <summary> 148 /// 当InputType为数字类型时,能输入的最小值 149 /// </summary> 
150 [Description("当InputType为数字类型时,能输入的最小值。")] 151 public decimal MinValue 152  
{153 get 154  { 155 return this._minValue; 156  } 157 set 158  { 159 this
._minValue = value; 160  } 161  } 162 /// <summary> 163 /// 
当InputType为数字类型时,能输入的最小值164 /// </summary> 165 [Description("
当InputType为数字类型时,小数位数。")] 166 public int DecLength 167  { 168 get 169  { 170 
return this._decLength; 171  } 172 set 173  { 174 this._decLength = value; 175  
}176  } 177 178 public TextBoxEx() 179  { 180 this.InitializeComponent(); 181 
base.GotFocus += new EventHandler(this.TextBoxEx_GotFocus); 182 base.MouseUp += 
new MouseEventHandler(this.TextBoxEx_MouseUp); 183 base.KeyPress += 
TextBoxEx_KeyPress;184  } 185 186 void TextBoxEx_KeyPress(object sender, 
KeyPressEventArgs e)187  { 188 //以下代码 取消按下回车或esc的“叮”声 189 if (e.KeyChar == 
System.Convert.ToChar(13) || e.KeyChar == System.Convert.ToChar(27)) 190  { 191 
e.Handled =true; 192  } 193  } 194 195 private void TextBoxEx_MouseUp(object 
sender, MouseEventArgs e)196  { 197 if (this.blnFocus) 198  { 199 base
.SelectAll();200 this.blnFocus = false; 201  } 202  } 203 204 private void 
TextBoxEx_GotFocus(object sender, EventArgs e) 205  { 206 this.blnFocus = true; 
207 base.SelectAll(); 208  } 209 210 private void TextBoxEx_TextChanged(object 
sender, EventArgs e)211  { 212 if (this.Text == "") 213  { 214 this
.m_strOldValue =this.Text; 215  } 216 else if (this.m_strOldValue != this.Text) 
217  { 218 if (!ControlHelper.CheckInputType(this.Text, this._inputType, this
._maxValue,this._minValue, this._decLength, this._regexPattern)) 219  { 220 int 
num =base.SelectionStart; 221 if (this.m_strOldValue.Length < this.Text.Length) 
222  { 223 num--; 224  } 225 else 226  { 227 num++; 228  } 229 base.TextChanged 
-=new EventHandler(this.TextBoxEx_TextChanged); 230 this.Text = this
.m_strOldValue;231 base.TextChanged += new EventHandler(this
.TextBoxEx_TextChanged);232 if (num < 0) 233  { 234 num = 0; 235  } 236 base
.SelectionStart = num; 237  } 238 else 239  { 240 this.m_strOldValue = this
.Text;241  } 242  } 243  } 244 245 protected override void 
OnPaint(PaintEventArgs e)246  { 247 base.OnPaint(e); 248 if (string
.IsNullOrEmpty(this.Text) && !string.IsNullOrEmpty(this._promptText)) 249  { 250
if (e == null) 251  { 252 using (Graphics graphics = Graphics.FromHwnd(base
.Handle))253  { 254 if (this.Text.Length == 0 && !string.IsNullOrEmpty(this
.PromptText))255  { 256 TextFormatFlags textFormatFlags = 
TextFormatFlags.EndEllipsis | TextFormatFlags.VerticalCenter; 257 if (this
.RightToLeft == RightToLeft.Yes) 258  { 259 textFormatFlags |= 
(TextFormatFlags.Right | TextFormatFlags.RightToLeft); 260  } 261 
TextRenderer.DrawText(graphics,this.PromptText, this._promptFont, base
.ClientRectangle,this._promptColor, textFormatFlags); 262  } 263  } 264  } 265  
}266  } 267 268 protected override void WndProc(ref Message m) 269  { 270 base
.WndProc(ref m); 271 if (m.Msg == 15 || m.Msg == 7 || m.Msg == 8) 272  { 273 
this.OnPaint(null); 274  } 275  } 276 277 protected override void 
OnTextChanged(EventArgs e)278  { 279 base.OnTextChanged(e); 280 base
.Invalidate();281  } 282  } 283 } View Code 
用处及效果
用处:需要控制输入,需要显示水印
最后的话
如果你喜欢的话,请到 https://gitee.com/kwwwvagaa/net_winform_custom_control 
<https://gitee.com/kwwwvagaa/net_winform_custom_control> 点个星 星吧
热门工具 换一换