本文版權歸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