多年前写的文本框扩展控件(有ValueChanging事件等),已放github
本文版权归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所需的数据结构。
View Code1 /// <summary> 2 /// 正在改变EventArgs 3 /// </summary> 4 public class ChangingEventArgs : CancelEventArgs 5 { 6 private object newValue; 7 private object oldValue; 8 9 /// <summary> 10 /// 正在改变EventArgs 11 /// </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 /// 正在改变EventArgs 21 /// </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 NewValue 36 { 37 get 38 { 39 return this.newValue; 40 } 41 set 42 { 43 this.newValue = value; 44 } 45 } 46 47 /// <summary> 48 /// 原值 49 /// </summary> 50 public object OldValue 51 { 52 get 53 { 54 return this.oldValue; 55 } 56 } 57 }二:TextBoxEx控件
提供扩展的textbox功能。
1.委托及事件定义
这里没有简单的用事件参数,还是使用了事件属性,大家如果感兴趣,可以去看下msdn对这两块的解释,也没用简单的使用Action,因为你设计的时候写的简单了,方便了,易用了,但是别人调用的时候就不简单,方便了。
View Code1 /// <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 EditValueChanging 14 { 15 add 16 { 17 base.Events.AddHandler(editValueChanging, value); 18 } 19 remove 20 { 21 base.Events.RemoveHandler(editValueChanging, value); 22 } 23 }2.设计器阶段的界面输入
为了方便使用,就加入了设计器阶段属性,方便简单的输入。View Code1 /// <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 MinNum 15 { 16 get { return _minNum; } 17 set 18 { 19 if (value <= 0) 20 _minNum = value; 21 } 22 } 23 /// <summary> 24 /// 输入值类型 25 /// </summary> 26 [Description("输入值类型")] 27 public ValueType EditValueType 28 { 29 get { return _editValueType; } 30 set 31 { 32 _editValueType = value; 33 //设置初始值 34 if (value == ValueType.Number) 35 { 36 EditValue = 0; 37 } 38 else 39 EditValue = null; 40 } 41 }3.整体代码
其实也没什么技术含量,只是提供个思路。View Code1 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 set 102 { 103 if (EditValue == value) return; 104 OnEditValueChanging(new ChangingEventArgs(fEditValue, value)); 105 this.Text = fEditValue == null ? null : fEditValue.ToString(); 106 } 107 } 108 #endregion 109 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 else 151 { 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 else 171 { 172 fEditValue = e.OldValue; 173 return; 174 } 175 fEditValue = strOp; 176 } 177 else 178 fEditValue = e.OldValue;//还原 179 return; 180 } 181 if (intNewNum > MaxNum 182 || intNewNum < MinNum)//不在范围里的数据 183 { 184 fEditValue = e.OldValue; 185 return; 186 } 187 //同步设置新值 188 fEditValue = e.NewValue; 189 } 190 else 191 { 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 #endregion 236 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 #endregion 257 258 259 #region 枚举 260 /// <summary> 261 /// 改变值类型 262 /// </summary> 263 public enum ValueType 264 { 265 Number, 266 String, 267 } 268 #endregion 269 } 270 }
使用
由于是控件,所以没有采用UnitTest方式,而是建立一个winfrom窗体进行测试。
定义2个控件
texBoxEx1 字符串输入
tbxBoxEx2 数字型输入,最小值-200,最大值200
代码做了简单过滤
View Code1 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 //简单的过滤100 11 int temp = (int)e.NewValue; 12 if (temp == 100) 13 e.Cancel = true; 14 }测试结果如下:
对于tbxBoxEx1的输入abc,在输入c的时候就输入不进去了,换个d就可以输入进去了。
对于tbxBoxEx2,在输入-201的时候不能输入,201的时候也不能,100的时候也不能。由于验证机制是调用订阅的验证机制然后才是基类的验证机制,所以订阅的是做扩展用的。所以订阅的代码还是要做点异常处理,比如输入其他字符号。当时想的是默认情况下基类判断起作用,如果想做扩展,订阅这个事件,然后处理,但是现在过了这多年回来看,这块还是需要优化下,应该为了更方便的点,基类的判断应该是一直前的,这样可以少了很多异常判断,所以这里测试代码就简单的过滤100就行了,负数等的自行取消订阅事件里的代码。
GitHub
本文版权归mephisto和博客园共有,欢迎转载,但须保留此段声明,并给出原文链接,谢谢合作。
文章是哥(mephisto)写的,SourceLink