一、简单回顾

在前两节中,对Panel和GroupBox控件进行了相关的扩展应用,主要都是设置控件的边框以及边框颜色等。本节,继续对WinForm现有的控件TextBox进行扩展,来满足实际开发中的需要。

二、TextBox扩展

WinForm现有的TextBox控件功能已然相当强大了,但有些时候仍然不能满足一些实际开发的需要,本节针对开发中的需求问题,对控件进行了以下扩展:

1、 和以往一样,设置控件的边框问题,主要有:边框颜色、边框粗细;

2、 控件添加水印文字效果,可以设置水印文字颜色以及字体等;

3、 实现控件对常规输入项的验证效果,比如:数字、电话号码、电子邮件等;对不符合规则的输入进行错误提示。

(I)、边框扩展

为自定义控件添加边框颜色和边框粗细这两个属性;然后WinProc方法中重绘边框,是重新绘制一个矩形遮盖原有的线条,这里采用的方法和前两节基本相似。

(II)、水印提示

为控件添加水印效果的提示,方便于用户的输入提示,水印文字实际上就是通过TextRenderer的DrawText 方法将提示文字绘制到TextBox文本框中的。

(III)、输入验证

当用户在即时输入的过程中,就对输入内容进行规则验证,判断输入是否正确,若不正确,则提示输入出错。这里主要采用了正则表达式来进行验证,在用户输入过程中,触发OnTextChanged函数,然后验证输入的文本。

本节中主要可以进行如下验证:

默认、数字、汉字、邮政编码、电子邮件、座机电话号码、中国电话号码、手机号码、整数、负整数、浮点数、非负浮点数、正浮点数、非正浮点数、负浮点数、英文字符、大写英文字符、小写英文字符、数字和英文字母、数字、英文字母或下划线、URL、QQ、身份证、IP、"2000-2-28 23:29:59"、"2000-2-28"、年份、月份、日、"23:29:59"、"2000-02-29 10:29:39 pm"、"2009年2月28日"。

关键代码如下:

  1. protectedoverridevoid WndProc(ref Message m)
  2. {
  3. base.WndProc(ref m);
  4. this.BorderStyle = BorderStyle.FixedSingle;
  5. if (m.Msg == WM_PAINT || m.Msg == WM_NCPAINT)
  6. {
  7. if (this.BorderWeight % 2 == 0)
  8. {
  9. this.BorderWeight -= 1;
  10. }
  11. using (Graphics g = Graphics.FromHwnd(this.Handle))
  12. {
  13. using (Pen pen = new Pen(this.BorderColor, this.BorderWeight))
  14. {
  15. g.DrawRectangle(pen, 0, 0, Size.Width - 1, Size.Height - 1);
  16. }
  17. }
  18. WmPaint();
  19. }
  20. }
  21. privatevoid WmPaint()
  22. {
  23. using (Graphics graphics = Graphics.FromHwnd(base.Handle))
  24. {
  25. if (Text.Length == 0 && !string.IsNullOrEmpty(_waterMarkText) && !Focused)
  26. {
  27. TextFormatFlags format = TextFormatFlags.EndEllipsis | TextFormatFlags.VerticalCenter;
  28. if (RightToLeft == RightToLeft.Yes)
  29. {
  30. format |= TextFormatFlags.RightToLeft | TextFormatFlags.Right;
  31. }
  32. TextRenderer.DrawText(graphics, _waterMarkText, this.WaterMarkFont, base.ClientRectangle, _waterMarkTextColor, format);
  33. }
  34. }
  35. }
  1. protectedoverridevoid OnTextChanged(System.EventArgs e)
  2. {
  3. if (this.Text != " ")
  4. {
  5. bool b = Invalid(this.ControlType, this.Text);
  6. if (!b)
  7. {
  8. this.BorderColor = Color.Red;
  9. }
  10. else
  11. {
  12. this.BorderColor = r;
  13. }
  14. }
  15. else
  16. {
  17. WmPaint();
  18. }
  19. base.Invalidate();
  20. }
  21. privatebool Invalid(RegexType value, string text)
  22. {
  23. bool b = false;
  24. switch (value)
  25. {
  26. case RegexType.Custom:
  27. b = true;
  28. break;
  29. case RegexType.Number:
  30. b = Validation(text, @"^\d+$");
  31. break;
  32. case RegexType.CNString:
  33. b = Validation(text, @"^[\u4e00-\u9fa5]$");
  34. break;
  35. case RegexType.Zip:
  36. b = Validation(text, @"^[1-9]\d{5}$");
  37. break;
  38. case RegexType.Email:
  39. b = Validation(text, @"^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$");
  40. break;
  41. case RegexType.Phone:
  42. b = Validation(text, @"^((\(\d{2,3}\))|(\d{3}\-))?(\(0\d{2,3}\)|0\d{2,3}-)?[1-9]\d{6,7}(\-\d{1,4})?$");
  43. break;
  44. case RegexType.CNPhone:
  45. b = Validation(text, @"^\d{3}-\d{8}|\d{4}-\d{7}$");
  46. break;
  47. case RegexType.Mobile:
  48. b = Validation(text, @"^((\(\d{2,3}\))|(\d{3}\-))?13\d{9}$");
  49. break;
  50. case RegexType.Integer:
  51. b = Validation(text, @"^-?\d+$");
  52. break;
  53. case RegexType.NInteger:
  54. b = Validation(text, @"^-[0-9]*[1-9][0-9]*$");
  55. break;
  56. case RegexType.Float:
  57. b = Validation(text, @"^(-?\d+)(\.\d+)?$");
  58. break;
  59. case RegexType.NNFloat:
  60. b = Validation(text, @"^\d+(\.\d+)?$");
  61. break;
  62. case RegexType.PFloat:
  63. b = Validation(text, @"^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*))$");
  64. break;
  65. case RegexType.NPFloat:
  66. b = Validation(text, @"^((-\d+(\.\d+)?)|(0+(\.0+)?))$");
  67. break;
  68. case RegexType.NFloat:
  69. b = Validation(text, @"^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$");
  70. break;
  71. case RegexType.ENChar:
  72. b = Validation(text, @"^[A-Za-z]+$");
  73. break;
  74. case RegexType.ENUChar:
  75. b = Validation(text, @"^[A-Z]+$");
  76. break;
  77. case RegexType.ENLChar:
  78. b = Validation(text, @"^[a-z]+$");
  79. break;
  80. case RegexType.MixChar:
  81. b = Validation(text, @"^[A-Za-z0-9]+$");
  82. break;
  83. case RegexType.MixLineChar:
  84. b = Validation(text, @"^\w+$");
  85. break;
  86. case RegexType.Url:
  87. b = Validation(text, @"^(?:https?|ftp)\:\/\/(?:(?:[a-z0-9\-\._~\!\$\&\'\(\)\*\+\,\;\=:]|%[0-9a-f]{2,2})*\@)?(?:((?:(?:[a-z0-9][a-z0-9\-]*[a-z0-9]|[a-z0-9])\.)*(?:[a-z][a-z0-9\-]*[a-z0-9]|[a-z])|(?:\[[^\]]*\]))(?:\:[0-9]*)?)(?:\/(?:[a-z0-9\-\._~\!\$\&\'\(\)\*\+\,\;\=\:\@]|%[0-9a-f]{2,2})*)*(?:\?(?:[a-z0-9\-\._~\!\$\&\'\(\)\*\+\,\;\=\:\@\/\?]|%[0-9a-f]{2,2})*)?(?:\#(?:[a-z0-9\-\._~\!\$\&\'\(\)\*\+\,\;\=\:\@\/\?]|%[0-9a-f]{2,2})*)?$");
  88. break;
  89. case RegexType.QQ:
  90. b = Validation(text, @"^[1-9][0-9]{4,}$");
  91. break;
  92. case RegexType.DCard:
  93. b = Validation(text, @"^((1[1-5])|(2[1-3])|(3[1-7])|(4[1-6])|(5[0-4])|(6[1-5])|71|(8[12])|91)\d{4}((19\d{2}(0[13-9]|1[012])(0[1-9]|[12]\d|30))|(19\d{2}(0[13578]|1[02])31)|(19\d{2}02(0[1-9]|1\d|2[0-8]))|(19([13579][26]|[2468][048]|0[48])0229))\d{3}(\d|X|x)?$");
  94. break;
  95. case RegexType.IP:
  96. b = Validation(text, @"^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$");
  97. break;
  98. case RegexType.DateTime:
  99. b = Validation(text, @"^((((1[6-9]|[2-9]\d)\d{2})-(0?[13578]|1[02])-(0?[1-9]|[12]\d|3[01]))|(((1[6-9]|[2-9]\d)\d{2})-(0?[13456789]|1[012])-(0?[1-9]|[12]\d|30))|(((1[6-9]|[2-9]\d)\d{2})-0?2-(0?[1-9]|1\d|2[0-8]))|(((1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))-0?2-29-)) (20|21|22|23|[0-1]?\d):[0-5]?\d:[0-5]?\d$");
  100. break;
  101. case RegexType.Date:
  102. b = Validation(text, @"^((((1[6-9]|[2-9]\d)\d{2})-(0?[13578]|1[02])-(0?[1-9]|[12]\d|3[01]))|(((1[6-9]|[2-9]\d)\d{2})-(0?[13456789]|1[012])-(0?[1-9]|[12]\d|30))|(((1[6-9]|[2-9]\d)\d{2})-0?2-(0?[1-9]|1\d|2[0-8]))|(((1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))-0?2-29-))$");
  103. break;
  104. case RegexType.Year:
  105. b = Validation(text, @"^((1[6-9]|[2-9]\d)\d{2})$");
  106. break;
  107. case RegexType.Month:
  108. b = Validation(text, @"^(0?[123456789]|1[012])$");
  109. break; span>
  110. case RegexType.Day:
  111. b = Validation(text, @"^(0?[1-9]|[12]\d|3[01])$");
  112. break;
  113. case RegexType.Time:
  114. b = Validation(text, @"^(20|21|22|23|[0-1]?\d):[0-5]?\d:[0-5]?\d$");
  115. break;
  116. case RegexType.DateTimeAm:
  117. b = Validation(text, @"^((\d{2}(([02468][048])|([13579][26]))[\-\/\s]?((((0?[13578])|(1[02]))[\-\/\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\-\/\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\-\/\s]?((0?[1-9])|([1-2][0-9])))))|(\d{2}(([02468][1235679])|([13579][01345789]))[\-\/\s]?((((0?[13578])|(1[02]))[\-\/\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\-\/\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\-\/\s]?((0?[1-9])|(1[0-9])|(2[0-8]))))))(\s(((0?[1-9])|(1[0-2]))\:([0-5][0-9])((\s)|(\:([0-5][0-9])\s))([AM|PM|am|pm]{2,2})))?$");
  118. break;
  119. case RegexType.Date2:
  120. b = Validation(text, @"^((((1[6-9]|[2-9]\d)\d{2})年(0?[13578]|1[02])月(0?[1-9]|[12]\d|3[01])日)|(((1[6-9]|[2-9]\d)\d{2})年(0?[13456789]|1[012])月(0?[1-9]|[12]\d|30)日)|(((1[6-9]|[2-9]\d)\d{2})年0?2月(0?[1-9]|1\d|2[0-8])日)|(((1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))年0?2月29日))$");
  121. break;
  122. }
  123. return b;
  124. }
  125. privatebool Validation(string validValue, string regularExpression)
  126. {
  127. Regex regex;
  128. try
  129. {
  130. regex = new Regex(regularExpression);
  131. }
  132. catch
  133. {
  134. returnfalse;
  135. }
  136. if (regex.IsMatch(validValue))
  137. {
  138. returntrue;
  139. }
  140. else
  141. {
  142. returnfalse;
  143. }
  144. }

关键代码就是这么多,其实也都很简单,下面来看下实现的效果:

控件完成后,添加到窗体当中,则有如下自定义属性:

控件运行效果如下:

运行状态下,红色边框的为出错提示。

三、关联知识补遗

1、C#TextRenderer类相关应用

TextRenderer 类提供了一组 static 方法,可用于在 Windows 窗体控件上测量和绘制文本。

2、正则表达式的相关应用

C#中的正则表达式包含在.NET基础类库的一个名称空间下,这个名称空间是System.Text.RegularExpressions。

该命名空间包括8个类,1个枚举,1个委托。他们分别是:
Capture: 包含一次匹配的结果;
CaptureCollection: Capture的序列;
Group: 一次组记录的结果,由Capture继承而来;
GroupCollection:表示捕获组的集合
Match: 一次表达式的匹配结果,由Group继承而来;
MatchCollection: Match的一个序列;
MatchEvaluator: 执行替换操作时使用的委托;
Regex:编译后的表达式的实例。
RegexCompilationInfo:提供编译器用于将正则表达式编译为独立程序集的信息
RegexOptions 提供用于设置正则表达式的枚举值
Regex类中还包含一些静态的方法:
Escape: 对字符串中的regex中的转义符进行转义;
IsMatch: 如果表达式在字符串中匹配,该方法返回一个布尔值;
Match: 返回Match的实例;
Matches: 返回一系列的Match的方法;
Replace: 用替换字符串替换匹配的表达式;
Split: 返回一系列由表达式决定的字符串;
Unescape:不对字符串中的转义字符转义。

正则表达式在C#中的应该很简单就是一个简单的匹配,但是如何去写这个表达式则需要技巧和实践。

[PS:补充源代码下载]源代码

最新文章

  1. CMake undefined reference to `QTcpServer::QTcpServer(QObject*)'的解决
  2. Oracle 数据库 基础学习 (一) SQL基本知识
  3. MVC ViewBag和ViewData的区别
  4. mysql颠覆实战笔记(二)-- 用户登录(一):唯一索引的妙用
  5. OSI与TCP/IP模型之比较
  6. ByteArrayInputStream 和 ByteArrayOutputStream
  7. Wii硬盘版玩机心得
  8. Gym 100553B Burrito King 无脑背包
  9. java 反射的实例
  10. Java框架之Hibernate(二)
  11. 卡尔曼滤波法C编程
  12. Spring源码分析(一)--BeanProcessor
  13. 利用numpy+matplotlib绘图的基本操作教程
  14. Vim使用技巧:特定文件类型关联缩进
  15. 文本不能被选中的css
  16. 个人对于angularjs依赖注入的理解
  17. vi/vim tab键空格数修改
  18. c++ 11 override final
  19. Devenv 命令行开关
  20. Hadoop2.0产生背景

热门文章

  1. 【BZOJ】4025: 二分图
  2. Linux 彻底删除用户
  3. 最小生成树问题(prim算法)POJ-1258 Agri-Net
  4. ES8之async/await学习随笔
  5. 前端页面重构技巧总结TIP【持续更新...】
  6. Codeforces.1041F.Ray in the tube(思路)
  7. BZOJ.3522.[POI2014]Hotel(DP)
  8. 编码自动识别工具 uchardet
  9. BZOJ4205 : 卡牌配对
  10. 【BZOJ-4408】神秘数 可持久化线段树