1. 先创建一个项目,在工具栏里点击鼠标右键,弹出菜单中选择“选择项”,接着在弹出的窗口中选择“.net framework组件”面板,点击下面“浏览”按钮后选中“TzhTechUcLibrary.dll”,点击确定,这样就将控件添加到工具栏里了(不要怪我啰嗦哈,要考虑新手):
2. 在Form1窗体上,添加2个Groupbox控件,7个Label,6个RegexTextBox和2个Button,如图所示:
3. 分别设置regexTextBox1~5的“验证”栏属性为如下图示:
regexTextBox1(正则表达式为:^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*):
regexTextBox2(正则表达式为:^[+-]?\d*[.]?\d*$):
regexTextBox3(正则表达式为:^[+-]?\d*[.]?\d*$):
regexTextBox4(正则表达式为:^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*):
regexTextBox5(注意,Validate属性设置为了Customer):
regexTextBox6(正则表达式为:^[+-]?\d*[.]?\d*$):
4. 双击button1,编写事件:
private void button1_Click(object sender, EventArgs e)
{
MessageBox.Show("button1所有文本框通过验证");
}
button2事件:
private void button2_Click(object sender, EventArgs e)
{
MessageBox.Show("button2所有文本框通过验证");
}
regexTextBox5切换到事件面板,找到“验证”项,双击CustomerValidated:
编写代码:
- private void regexTextBox5_CustomerValidated(object sender, TzhTechUcLibrary.CustomerEventArgs e)
- {
- if (e.Value.Length < 6 || e.Value.Length > 16)
- {
- e.ErrorMessage = "输入的字符串长度必须要在6~16位之间";
- e.Validated = false;
- }
- }
private void regexTextBox5_CustomerValidated(object sender, TzhTechUcLibrary.CustomerEventArgs e)
{
if (e.Value.Length < 6 || e.Value.Length > 16)
{
e.ErrorMessage = "输入的字符串长度必须要在6~16位之间";
e.Validated = false;
}
}
到此为止,界面设置全部完成,接下来运行程序查看结果:
点击button1后产生的结果:
regexTextBox1允许为空,所有没有输入则不验证:
regexTextBox1输入了不合法的邮箱格式:
regexTextBox3没有输入错误信息显示在label7上:
regexTextBox3不满足正则表达式的情况:
regexTextBox4不允许为空,文本框背景出现警告色:
全部验证通过后,执行了button1_Click事件:
点击button2产生的效果:
regexTextBox5调用的是自定义验证事件CustomerValidated进行验证:
该控件的最大优势在于开发人员无需在对文本框进行任何的验证,也不用编写任何代码进行处理,简化了代码,加快开发速度。
核心源码:
首先,添加一个接口类:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows.Forms; using System.ComponentModel; namespace Tzhtec.Controls { /// <summary> /// 为自定义验证事件提供参数 /// </summary> [Description("为自定义验证事件提供参数"), Browsable(false)] public class CustomerEventArgs : EventArgs { /// <summary> /// 是否通过验证 /// </summary> [Description("是否通过验证"), DefaultValue(true)] public bool Validated { get; set; } /// <summary> /// 获取或设置被验证的值 /// </summary> [Description("获取或设置被验证的值")] public string Value { get; set; } /// <summary> /// 获取或设置错误信息 /// </summary> [Description("获取或设置错误信息")] public string ErrorMessage { get; set; } } public delegate void CustomerValidatedHandler(object sender, CustomerEventArgs e); public interface ITzhtecControl { ButtonBase Button { get; set; } string RegexExpression { get; set; } bool AllowEmpty { get; set; } bool RemoveSpace { get; set; } string EmptyMessage { get; set; } string ErrorMessage { get; set; } void SelectAll(); event CustomerValidatedHandler CustomerValidated; } }
这个接口,用于自定义控件的扩展,实现属性的设置等功能。接着,我们需要对按钮进行功能扩展,有属性的扩展只有在VS2008以后版本才有,所以使用VS2005和之前版本无法使用本功能。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows.Forms; using System.ComponentModel; using System.Text.RegularExpressions; using System.Collections; using System.Reflection; namespace Tzhtec.Controls { /// <summary> /// 创建:天智海网络 /// 邮箱:service@tzhtec.com /// 网址:http://www.tzhtec.com /// 功能描述:BaseButton扩展方法 /// </summary> public static class TzhtecButton { private static Hashtable ht = new Hashtable(); // 存储相关控件与对应的按钮关系 private static Hashtable eventHt = new Hashtable(); // 存储按钮原有事件 private static ToolTip _tooltip; // 控件的tooltip /// <summary> /// 将控件添加到控制列表 /// </summary> /// <param name="baseButton"></param> /// <param name="control"></param> public static void AddControl(this ButtonBase baseButton, Control control) { if (control as ITzhtecControl == null) return; if (!ht.ContainsKey(control)) { ht.Add(control, baseButton); HookButtonClickEvent(baseButton); control.TextChanged += new EventHandler(control_TextChanged); } } /// <summary> /// 将控件从控制列表移除 /// </summary> /// <param name="baseButton"></param> /// <param name="control"></param> public static void RemoveControl(this ButtonBase baseButton, Control control) { if (control as ITzhtecControl == null) return; if (ht.ContainsKey(control)) { ht.Remove(control); RemoveHookEvent(baseButton); control.TextChanged -= new EventHandler(control_TextChanged); } } /// <summary> /// 文本改变消除提示信息 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private static void control_TextChanged(object sender, EventArgs e) { if (_tooltip != null) _tooltip.Dispose(); } /// <summary> /// 捕获按钮click事件 /// </summary> /// <param name="baseButton"></param> private static void HookButtonClickEvent(ButtonBase baseButton) { if (baseButton == null) return; if (eventHt.Contains(baseButton)) return; PropertyInfo pi = baseButton.GetType().GetProperty ("Events", BindingFlags.Instance | BindingFlags.NonPublic); if (pi != null) { //获得事件列表 EventHandlerList eventList = (EventHandlerList)pi.GetValue (baseButton, null); if (eventList != null && eventList is EventHandlerList) { //查找按钮点击事件 FieldInfo fi = (typeof(Control)).GetField("EventClick", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.IgnoreCase); if (fi != null) { EventHandler eh = eventList[fi.GetValue(baseButton)] as EventHandler; //记录原有按钮事件 if (eh != null) baseButton.Click -= eh; //移除原有的按钮事件 baseButton.Click += new EventHandler(button_Click); //替换按钮事件 eventHt.Add(baseButton, eh); } } } } /// <summary> /// 还原按钮click事件 /// </summary> /// <param name="baseButton"></param> private static void RemoveHookEvent(ButtonBase baseButton) { if (!ht.ContainsValue(baseButton)) { foreach (DictionaryEntry de in eventHt) //遍历hashtable得到与之相关的按钮 { if (de.Key == baseButton) { EventHandler eh = de.Value as EventHandler; baseButton.Click -= button_Click; //移除替换事件 baseButton.Click += eh; // 还原事件 break; } } eventHt.Remove(baseButton); } } /// <summary> /// 替换按钮的click事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private static void button_Click(object sender, EventArgs e) { if (sender == null) return; // 获取当前按钮相关的所有控件,并根据tabindex升序排序 var ctls = (from item in ht.Cast<DictionaryEntry>() where item.Value == sender as ButtonBase select item.Key as Control).Distinct().OrderBy(c => c.TabIndex); foreach (var ctl in ctls) { // 未激活或者已隐藏控件不验证 if (!(ctl.Enabled && ctl.Visible && ctl.Parent.Visible && ctl.Parent.Enabled)) continue; ITzhtecControl c = ctl as ITzhtecControl; if (c != null) { if (!EmptyValidate(ctl)) return; if (!RegexExpressionValidate(ctl)) return; if (!InvokeCustomerEvent(ctl)) return; } } foreach (DictionaryEntry de in eventHt) //遍历hashtable得到与之相关的按钮 { if (de.Key == sender as ButtonBase) { EventHandler eh = de.Value as EventHandler; if (eh != null) eh(sender, e); break; } } } /// <summary> /// 非空验证 /// </summary> /// <param name="ctl"></param> /// <returns></returns> private static bool EmptyValidate(Control ctl) { ITzhtecControl c = ctl as ITzhtecControl; if (!c.AllowEmpty) { if ((c.RemoveSpace && ctl.Text.Trim() == "") || ctl.Text == "") { ShowErrorMessage(ctl, c.EmptyMessage); c.SelectAll(); ctl.Focus(); return false; } } return true; } /// <summary> /// 正则验证 /// </summary> /// <param name="ctl"></param> /// <returns></returns> private static bool RegexExpressionValidate(Control ctl) { ITzhtecControl c = ctl as ITzhtecControl; if (!((c.RemoveSpace && ctl.Text.Trim() == "") || ctl.Text == "")) { if (!string.IsNullOrEmpty(c.RegexExpression) && !Regex.IsMatch((c.RemoveSpace ? ctl.Text.Trim() : ctl.Text), c.RegexExpression)) { ShowErrorMessage(ctl, c.ErrorMessage); c.SelectAll(); ctl.Focus(); return false; } } return true; } /// <summary> /// 自定义验证 /// </summary> /// <param name="ctl"></param> /// <returns></returns> private static bool InvokeCustomerEvent(Control ctl) { PropertyInfo pi = ctl.GetType().GetProperty("Events", BindingFlags.Instance | BindingFlags.NonPublic); if (pi != null) { EventHandlerList ehl = (EventHandlerList)pi.GetValue(ctl, null); if (ehl != null) { // 得到自定义验证事件 FieldInfo fi = ctl.GetType().GetField("CustomerValidated", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); if (fi != null) { Delegate d = fi.GetValue(ctl) as Delegate; if (d != null) { CustomerEventArgs ce = new CustomerEventArgs(); ce.Value = ctl.Text; ce.Validated = true; d.DynamicInvoke(ctl, ce); // 执行自定义验证方法 if (!ce.Validated) { ShowErrorMessage(ctl, ce.ErrorMessage); (ctl as ITzhtecControl).SelectAll(); ctl.Focus(); return false; } } } } } return true; } /// <summary> /// 显示提示信息 /// </summary> /// <param name="ctl"></param> /// <param name="err"></param> private static void ShowErrorMessage(Control ctl, string err) { if (_tooltip != null) _tooltip.Dispose(); // 如果tooltip已经存在则销毁 _tooltip = new ToolTip(); _tooltip.ToolTipIcon = ToolTipIcon.Warning; _tooltip.IsBalloon = true; _tooltip.ToolTipTitle = "提示"; _tooltip.AutoPopDelay = 5000; //得到信息显示的行数 if (err == null) err = " "; int l = err.Split(new string[] { "\r\n", "\r", "\n" }, StringSplitOptions.RemoveEmptyEntries).Length; _tooltip.Show(err, ctl, new System.Drawing.Point(10, -47 - l * 18 + (ctl.Height - 21) / 2)); } } }
至此,实现能够自己验证的控件核心代码已经完成,接下去就是以上2个类的使用。以下以TextBox为例说明,如果需要将其他控件实现自定义验证,使用同理方式新建相应的自定义组件即可。
先新建一个类,名为RegTextBox,然后修改该类继承关系如下:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Linq; using System.Text; using System.Windows.Forms; using Tzhtec.Controls; namespace MyTestControl { public partial class RegTextBox : TextBox, ITzhtecControl { #region ITzhtecControl 成员 private ButtonBase btn; // 获取或设置验证控件的按钮 ///[Description("获取或设置验证控件的按钮"), Category("验证"), DefaultValue(true)] public ButtonBase Button { get { return btn; } set { if (!DesignMode && hasCreate) { if (value == null) btn.RemoveControl(this); else btn.AddControl(this); } btn = value; } } private string _regExp = string.Empty; // 获取或设置用于验证控件值的正则表达式 ///[Description("获取或设置用于验证控件值的正则表达式"), Category("验证"), DefaultValue("")] public string RegexExpression { get { return _regExp; } set { _regExp = value; } } private bool _allEmpty = false; // 获取或设置是否允许空值 ///[Description("获取或设置是否允许空值"), Category("验证"), DefaultValue(true)] public bool AllowEmpty { get { return _allEmpty; } set { _allEmpty = value; } } private bool _removeSpace = false; // 获取或设置验证的时候是否除去头尾空格 ///[Description("获取或设置验证的时候是否除去头尾空格"), Category("验证"), DefaultValue(false)] public bool RemoveSpace { get { return _removeSpace; } set { _removeSpace = value; } } private string _empMsg = string.Empty; // 获取或设置当控件的值为空的时候显示的信息 ///[Description("获取或设置当控件的值为空的时候显示的信息"), Category("验证"), DefaultValue("")] public string EmptyMessage { get { return _empMsg; } set { _empMsg = value; } } private string _errMsg = string.Empty; // 获取或设置当不满足正则表达式结果的时候显示的错误信息 ///[Description("获取或设置当不满足正则表达式结果的时候显示的错误信息"), Category ("验证"), DefaultValue("")] public string ErrorMessage { get { return _errMsg; } set { _errMsg = value; } } public event CustomerValidatedHandler CustomerValidated; public void SelectAll() { base.SelectAll(); } #endregion private bool hasCreate = false; protected override void OnCreateControl() { base.OnCreateControl(); if (btn != null) btn.AddControl(this); hasCreate = true; } protected override void Dispose(bool disposing) { if (btn != null) btn.RemoveControl(this); base.Dispose(disposing); } } }
接着,编译下程序后在工具栏里就会出现RegTextBox的自定义控件,新建一个窗体后往窗体上拖放一个RegTextBox后就可以在“验证”栏目设置相应属性来实现验证功能了。