本文版权归mephisto和博客园共有,欢迎转载,但须保留此段声明,并给出原文链接,谢谢合作。
文章是哥(mephisto)写的,SourceLink
阅读目录
本文版权归mephisto和博客园共有,欢迎转载,但须保留此段声明,并给出原文链接,谢谢合作。
文章是哥(mephisto)写的,SourceLink
介绍
这个TextBoxEx控件是cs下的,为了广大的框架都能用,就基于Framework2.0,主要有原来的textbox的功能,然后追加了EditValueChanging,数字类型输入,最大值,最小值。大家可以看完后追加下功能,比如正则输入。
起因
也是5年前的事情了,当时在做cs,一般cs都会用第三方控件,比如Dev等,dev中就有很多人性化的控件,比如我们用的比较多textbox,他就有EditValueChanging事件,当时我就想,不可能所以的小项目还要用到dev,那又想自己用到这么方便的控件怎么办,于是我就开始自己做了这个控件,抛砖引玉,只是丰富了一点,但确实对我那个年代的技术提高起了些许作用。
代码
我们先看下项目结构,因为就一个扩展控件,所以整体上看,组织结构很简单。如图:
在ControlsEx这个工程中,主要一个自定义的事件所需参数ChangingEventArgs和一个扩展控件TextBoxEx。
一:ChangingEventArgs:
主要定义EditValueChanging所需的数据结构。
1 /// <summary> 2 /// 正在改变EventArgs 3 /// </summary> 4 public class ChangingEventArgs : CancelEventArgs 5 { 6 private object newValue; 7 private object oldValue; 8 9 /// <summary>10 /// 正在改变EventArgs11 /// </summary>12 /// <param name="oldValue">原值</param>13 /// <param name="newValue">新值</param>14 public ChangingEventArgs(object oldValue, object newValue)15 : this(oldValue, newValue, false)16 {17 }18 19 /// <summary>20 /// 正在改变EventArgs21 /// </summary>22 /// <param name="oldValue">原值</param>23 /// <param name="newValue">新值</param>24 /// <param name="cancel">是否取消</param>25 public ChangingEventArgs(object oldValue, object newValue, bool cancel)26 : base(cancel)27 {28 this.oldValue = oldValue;29 this.newValue = newValue;30 }31 32 /// <summary>33 /// 新值34 /// </summary>35 public object NewValue36 {37 get38 {39 return this.newValue;40 }41 set42 {43 this.newValue = value;44 }45 }46 47 /// <summary>48 /// 原值49 /// </summary>50 public object OldValue51 {52 get53 {54 return this.oldValue;55 }56 }57 }
View Code
二:TextBoxEx控件
提供扩展的textbox功能。
1.委托及事件定义
这里没有简单的用事件参数,还是使用了事件属性,大家如果感兴趣,可以去看下msdn对这两块的解释,也没用简单的使用Action,因为你设计的时候写的简单了,方便了,易用了,但是别人调用的时候就不简单,方便了。
1 /// <summary> 2 /// 改变中事件句柄 3 /// </summary> 4 /// <param name="sender"></param> 5 /// <param name="e"></param> 6 public delegate void ChangingEventHandler(object sender, ChangingEventArgs e); 7 8 /// <summary> 9 /// <para>值改变中事件10 /// </para>11 /// </summary>12 [Description("值改变中事件"), Category("事件")]13 public event ChangingEventHandler EditValueChanging14 {15 add16 {17 base.Events.AddHandler(editValueChanging, value);18 }19 remove20 {21 base.Events.RemoveHandler(editValueChanging, value);22 }23 }
View Code
2.设计器阶段的界面输入
为了方便使用,就加入了设计器阶段属性,方便简单的输入。
1 /// <summary> 2 /// 输入的最大值 3 /// </summary> 4 [Description("输入的最大值")] 5 public Int32 MaxNum 6 { 7 get { return _maxNum; } 8 set { _maxNum = value; } 9 }10 /// <summary>11 /// 输入的最小值12 /// </summary>13 [Description("输入的最小值")]14 public Int32 MinNum15 {16 get { return _minNum; }17 set18 {19 if (value <= 0)20 _minNum = value;21 }22 }23 /// <summary>24 /// 输入值类型25 /// </summary>26 [Description("输入值类型")]27 public ValueType EditValueType28 {29 get { return _editValueType; }30 set31 {32 _editValueType = value;33 //设置初始值34 if (value == ValueType.Number)35 {36 EditValue = 0;37 }38 else39 EditValue = null;40 }41 }
View Code
3.整体代码
其实也没什么技术含量,只是提供个思路。
1 public class TextBoxEx:TextBox 2 { 3 #region 委托 4 /// <summary> 5 /// 改变中事件句柄 6 /// </summary> 7 /// <param name="sender"></param> 8 /// <param name="e"></param> 9 public delegate void ChangingEventHandler(object sender, ChangingEventArgs e); 10 #endregion 11 12 #region 参数 13 private Int32 _maxNum = Int32.MaxValue;//最大值 14 private Int32 _minNum = Int32.MinValue;//最小值 15 private ValueType _editValueType = ValueType.String; 16 private static readonly object editValueChanging = new object();//EditValueChanging事件对应的Key 17 #endregion 18 19 #region Protected 参数 20 /// <summary> 21 /// 编制值 22 /// </summary> 23 protected object fEditValue = null; 24 /// <summary> 25 /// 编辑原始值 26 /// </summary> 27 protected object fOldEditValue = null; 28 #endregion 29 30 #region 公有属性 31 /// <summary> 32 /// 输入的最大值 33 /// </summary> 34 [Description("输入的最大值")] 35 public Int32 MaxNum 36 { 37 get { return _maxNum; } 38 set { _maxNum = value; } 39 } 40 /// <summary> 41 /// 输入的最小值 42 /// </summary> 43 [Description("输入的最小值")] 44 public Int32 MinNum 45 { 46 get { return _minNum; } 47 set 48 { 49 if (value <= 0) 50 _minNum = value; 51 } 52 } 53 /// <summary> 54 /// 输入值类型 55 /// </summary> 56 [Description("输入值类型")] 57 public ValueType EditValueType 58 { 59 get { return _editValueType; } 60 set 61 { 62 _editValueType = value; 63 //设置初始值 64 if (value == ValueType.Number) 65 { 66 EditValue = 0; 67 } 68 else 69 EditValue = null; 70 } 71 } 72 73 #endregion 74 75 #region 事件属性 76 /// <summary> 77 /// <para>值改变中事件 78 /// </para> 79 /// </summary> 80 [Description("值改变中事件"), Category("事件")] 81 public event ChangingEventHandler EditValueChanging 82 { 83 add 84 { 85 base.Events.AddHandler(editValueChanging, value); 86 } 87 remove 88 { 89 base.Events.RemoveHandler(editValueChanging, value); 90 } 91 } 92 #endregion 93 94 #region 私有属性 95 /// <summary> 96 /// 编辑值 97 /// </summary> 98 private object EditValue 99 {100 get { return fEditValue; }101 set102 {103 if (EditValue == value) return;104 OnEditValueChanging(new ChangingEventArgs(fEditValue, value));105 this.Text = fEditValue == null ? null : fEditValue.ToString();106 }107 }108 #endregion109 110 #region 事件111 /// <summary>112 /// 编辑值正在改变事件113 /// </summary>114 /// <param name="e"></param>115 protected virtual void OnEditValueChanging(ChangingEventArgs e)116 {117 //调用注册的事件118 ReiseEditValueChanging(e);119 120 if (e.Cancel)//注册的事件取消 还原值121 {122 fEditValue = e.OldValue;123 return;124 }125 126 switch (_editValueType)127 {128 case ValueType.Number://数值类型129 {130 if (e.NewValue != null && !string.IsNullOrEmpty(e.NewValue.ToString()))//非空值131 {132 int intNewNum = 0;133 if (!Int32.TryParse(e.NewValue.ToString(), out intNewNum))//非数字134 {135 string strOp = e.NewValue.ToString();136 //负号137 if (ParseValueIsMinus(strOp))138 {139 strOp = strOp.Replace("-", "");140 141 int tempMin = 0;142 if (Int32.TryParse(strOp, out tempMin))143 {144 if (tempMin > Math.Abs(MinNum + 1))145 {146 fEditValue = e.OldValue;147 return;148 }149 }150 else151 {152 fEditValue = e.OldValue;153 return;154 }155 strOp = "-" + strOp;156 fEditValue = strOp;157 }158 else if (strOp.Contains("-"))//多负号情况159 {160 strOp = strOp.Replace("-", "");161 int tempMax = 0;162 if (Int32.TryParse(strOp, out tempMax))163 {164 if (tempMax > MaxNum)165 {166 fEditValue = e.OldValue;167 return;168 }169 }170 else171 {172 fEditValue = e.OldValue;173 return;174 }175 fEditValue = strOp;176 }177 else178 fEditValue = e.OldValue;//还原179 return;180 }181 if (intNewNum > MaxNum182 || intNewNum < MinNum)//不在范围里的数据183 {184 fEditValue = e.OldValue;185 return;186 }187 //同步设置新值188 fEditValue = e.NewValue;189 }190 else191 {192 //同步设置新值(特殊)193 fEditValue = 0;194 }195 } break;196 case ValueType.String:197 {198 fEditValue = e.NewValue;199 } break;200 default:201 {202 fEditValue = e.NewValue;203 } break;204 205 }206 }207 208 /// <summary>209 /// 值改变后事件210 /// </summary>211 /// <param name="e"></param>212 protected override void OnTextChanged(EventArgs e)213 {214 if (this.Text != null)215 this.SelectionStart = this.Text.Length;216 217 if (this.Text.Equals(EditValue))218 {219 return;220 }221 222 base.OnTextChanged(e);223 EditValue = this.Text;224 }225 226 /// <summary>227 /// 调用注册的事件228 /// </summary>229 /// <param name="e"></param>230 public void ReiseEditValueChanging(ChangingEventArgs e)231 {232 ChangingEventHandler handler = (ChangingEventHandler)this.Events[editValueChanging];233 if (handler != null) handler(this, e);234 }235 #endregion236 237 #region 内部方法238 /// <summary>239 /// 判断字符串是否是负数240 /// </summary>241 /// <param name="strOp"></param>242 /// <returns></returns>243 private bool ParseValueIsMinus(string strOp)244 {245 bool blReturn = false;246 247 int index = strOp.IndexOf('-');248 if (index >= 0)249 {250 index = strOp.IndexOf('-', index + 1);251 if (index < 0)252 blReturn = true;253 }254 return blReturn;255 }256 #endregion257 258 259 #region 枚举260 /// <summary>261 /// 改变值类型262 /// </summary>263 public enum ValueType264 {265 Number,266 String,267 } 268 #endregion269 }270 }
View Code
使用
由于是控件,所以没有采用UnitTest方式,而是建立一个winfrom窗体进行测试。
定义2个控件
texBoxEx1 字符串输入
tbxBoxEx2 数字型输入,最小值-200,最大值200
代码做了简单过滤
1 private void textBoxEx1_EditValueChanging(object sender, ControlsEx.ChangingEventArgs e) 2 { 3 //简单的过滤abc和100 4 if (e.NewValue.ToString() == "abc") 5 e.Cancel = true; 6 } 7 8 private void textBoxEx2_EditValueChanging(object sender, ControlsEx.ChangingEventArgs e) 9 {10 //简单的过滤10011 int temp = (int)e.NewValue;12 if (temp == 100)13 e.Cancel = true;14 }
View Code
测试结果如下:
对于tbxBoxEx1的输入abc,在输入c的时候就输入不进去了,换个d就可以输入进去了。
对于tbxBoxEx2,在输入-201的时候不能输入,201的时候也不能,100的时候也不能。由于验证机制是调用订阅的验证机制然后才是基类的验证机制,所以订阅的是做扩展用的。所以订阅的代码还是要做点异常处理,比如输入其他字符号。当时想的是默认情况下基类判断起作用,如果想做扩展,订阅这个事件,然后处理,但是现在过了这多年回来看,这块还是需要优化下,应该为了更方便的点,基类的判断应该是一直前的,这样可以少了很多异常判断,所以这里测试代码就简单的过滤100就行了,负数等的自行取消订阅事件里的代码。
GitHub
https://github.com/sinodzh/ControlsEx
本文版权归mephisto和博客园共有,欢迎转载,但须保留此段声明,并给出原文链接,谢谢合作。
文章是哥(mephisto)写的,SourceLink
原标题:多年前写的文本框扩展控件(有ValueChanging事件等),已放github
关键词:Git