備份一段程式碼,用於提前測試textbox輸入字元後的字串
阿新 • • 發佈:2021-07-15
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Windows; using System.Windows.Controls; using System.Windows.Input; namespace XYY.Windows.SAAS.WpfExtention.AttachedProperties { public class InputAttachedProperties { #region 附加屬性 public static bool GetEnableInputValidate(DependencyObject obj) { return (bool)obj.GetValue(EnableInputValidateProperty); } public static void SetEnableInputValidate(DependencyObject obj, bool value) { obj.SetValue(EnableInputValidateProperty, value); } //是否使用輸入校驗 public static readonly DependencyProperty EnableInputValidateProperty = DependencyProperty.RegisterAttached("EnableInputValidate", typeof(bool), typeof(InputAttachedProperties), new PropertyMetadata(false, (a, b) => { if (a is TextBox tb && b.NewValue is bool en) { if (en) { tb.PreviewTextInput += Tb_PreviewTextInput; tb.GotFocus += Tb_GotFocus; tb.TextChanged += Tb_TextChanged; tb.AcceptsReturn = false; tb.AcceptsTab = false; tb.PreviewDrop += Tb_PreviewDrop; CommandManager.AddPreviewExecutedHandler(tb, tbPreviewCommandExcute); //禁用輸入法 if (tb.IsInputMethodEnabled) { InputMethod.SetIsInputMethodEnabled(tb, false); InputMethod.Current.ImeState = InputMethodState.Off; } } else { tb.PreviewTextInput -= Tb_PreviewTextInput; tb.GotFocus -= Tb_GotFocus; tb.AcceptsReturn = true; tb.AcceptsTab = true; tb.PreviewDrop -= Tb_PreviewDrop; CommandManager.RemovePreviewExecutedHandler(tb, tbPreviewCommandExcute); //禁用輸入法 if (tb.IsInputMethodEnabled) { InputMethod.SetIsInputMethodEnabled(tb, true); InputMethod.Current.ImeState = InputMethodState.DoNotCare; } } } })); private static void Tb_GotFocus(object sender, RoutedEventArgs e) { var tb = sender as TextBox; tb.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.ApplicationIdle, new Action(() => { tb.SelectAll(); })); } public static bool GetIsNumber(DependencyObject obj) { return (bool)obj.GetValue(IsNumberProperty); } public static void SetIsNumber(DependencyObject obj, bool value) { obj.SetValue(IsNumberProperty, value); } //是否是數字 (不能有負號,小數) public static readonly DependencyProperty IsNumberProperty = DependencyProperty.RegisterAttached("IsNumber", typeof(bool), typeof(InputAttachedProperties), new PropertyMetadata(false)); public static bool GetIsAmount(DependencyObject obj) { return (bool)obj.GetValue(IsAmountProperty); } public static void SetIsAmount(DependencyObject obj, bool value) { obj.SetValue(IsAmountProperty, value); } //是否是金額 (可以有負號,小數) public static readonly DependencyProperty IsAmountProperty = DependencyProperty.RegisterAttached("IsAmount", typeof(bool), typeof(InputAttachedProperties), new PropertyMetadata(false)); public static int GetDecimalPlace(DependencyObject obj) { return (int)obj.GetValue(DecimalPlaceProperty); } public static void SetDecimalPlace(DependencyObject obj, int value) { obj.SetValue(DecimalPlaceProperty, value); } //小數位數 public static readonly DependencyProperty DecimalPlaceProperty = DependencyProperty.RegisterAttached("DecimalPlace", typeof(int), typeof(InputAttachedProperties), new PropertyMetadata(3)); #endregion #region 校驗方法 private static void tbPreviewCommandExcute(object sender, ExecutedRoutedEventArgs e) { var tb = sender as TextBox; var isNumber = GetIsNumber(sender as TextBox); var isAmount = GetIsAmount(sender as TextBox); if (e.Command == ApplicationCommands.Cut || e.Command == ApplicationCommands.Paste) { e.Handled = true; } if (e.Command is RoutedUICommand rc) { switch (rc.Name) { case "MoveUpByLine": case "MoveDownByLine": e.Handled = true; return; case "Space": if (isAmount || isNumber) e.Handled = true; return; case "DeletePreviousWord": case "DeleteNextWord": case "Backspace": case "Delete": var result = TestFutureText(null, sender as TextBox, rc.Name); //只有多個連續的0替換成只有一個 if (Regex.IsMatch(result, @"^-?00+$")) { tb.Text = Regex.Replace(result, @"0+", m => "0"); tb.CaretIndex = tb.Text.Length; e.Handled = true; return; } //小數刪得只有末尾的.,把.也刪了 if (Regex.IsMatch(result, @"\.0*$")) { tb.Text = Regex.Replace(result, @"\.0*$", m => string.Empty); tb.CaretIndex = tb.Text.Length; e.Handled = true; return; } //整數部分刪得只有-,把整數部分改為0 if (Regex.IsMatch(result, @"^-(?!\d)")) { tb.Text = result.Replace("-", "0"); tb.CaretIndex = 0; tb.SelectionStart = 0; tb.SelectionLength = 1; e.Handled = true; return; } //如果輸入了.,但是沒有整數部分,整數部分補0 if (Regex.IsMatch(result, @"^\.")) { tb.Text = "0" + result; tb.CaretIndex = 0; tb.SelectionStart = 0; tb.SelectionLength = 1; e.Handled = true; return; } //整數無意義的0去掉 //小數無意義的0去掉 if (Regex.IsMatch(result, @"(^.*\..*?)0+$")) { tb.Text = Regex.Match(result, @"(^.*\..*?)0+$").Groups[1].Value; tb.CaretIndex = tb.Text.Length; e.Handled = true; return; } break; default: break; } } } private static void Tb_PreviewDrop(object sender, DragEventArgs e) { e.Handled = true; return; } private static void Tb_PreviewTextInput(object sender, System.Windows.Input.TextCompositionEventArgs e) { var previewText = e.Text; var tb = sender as TextBox; //禁用輸入法 if (tb.IsInputMethodEnabled) { InputMethod.SetIsInputMethodEnabled(tb, false); InputMethod.Current.ImeState = InputMethodState.Off; } var result = TestFutureText(previewText, tb); var isNumber = GetIsNumber(tb); var isAmount = GetIsAmount(tb); var decimalSpace = GetDecimalPlace(tb); //isAmoust和isNumber互斥,且優先順序高於isNumber if (isAmount) isNumber = false; if (isNumber || isAmount) { //不能輸入空格 if (Regex.IsMatch(result, @"\s+")) { e.Handled = true; return; } //全0的時候 ,多個連線的0替換成只有一個 if (Regex.IsMatch(result, @"^-?00+$")) { tb.Text = Regex.Replace(result, @"0+", m => "0"); tb.CaretIndex = tb.Text.Length; e.Handled = true; return; } } //純數字模式 if (isNumber) { //如果不是純數字,處理掉輸入訊號 if (!Regex.IsMatch(result, @"^\d+$")) { e.Handled = true; return; } //如果只輸了0再輸其他的數字,直接替換掉0 if (tb.Text == "0" && tb.SelectionLength == 0 && tb.CaretIndex == 1) { tb.Text = previewText; tb.CaretIndex = 1; e.Handled = true; return; } //不能輸入沒有意義的0 if (Regex.IsMatch(result, @"^0(?=\d)")) { e.Handled = true; return; } } //金額模式(正負值 小數點) if (isAmount) { //只能輸入數字和小數點和負號 if (!Regex.IsMatch(previewText, @"[\d\.\-]")) { e.Handled = true; return; } //如果游標右邊是. 什麼都不做,游標右移一位 if (Regex.IsMatch(tb.Text, @"\d+\.\d+") && previewText == "." && tb.Text.Length != tb.CaretIndex && tb.Text[tb.CaretIndex] == '.') { tb.CaretIndex++; } //小數點如果超過限制,中斷輸入訊號 if (Regex.IsMatch(result, @"\.\d+$")) { var len = Regex.Match(result, @"\.(\d+$)").Groups[1].Length; if (len > decimalSpace) { e.Handled = true; return; } } //如果是-.的情況 改為-0.1 if (result == "-.") { tb.Text = "-0.1"; tb.CaretIndex = tb.Text.Length - 1; tb.SelectionStart = tb.Text.Length - 1; tb.SelectionLength = 1; e.Handled = true; return; } if (result == ".") { tb.Text = "0.1"; tb.CaretIndex = tb.Text.Length - 1; tb.SelectionStart = tb.Text.Length - 1; tb.SelectionLength = 1; e.Handled = true; return; } //如果有多個小數點不讓輸入 if (Regex.Matches(result, @"\.").Count > 1) { e.Handled = true; return; } //如果有多個負號不讓輸入 if (Regex.Matches(result, @"\-").Count > 1) { e.Handled = true; return; } //如果負號不是在最前面不讓輸入 if (Regex.IsMatch(result, @"(?<!^)\-")) { e.Handled = true; return; } //不能輸入空格 if (Regex.IsMatch(result, @"\s+")) { e.Handled = true; return; } //整數部分如果只輸了0或-0,游標定位在0後面再輸其他的數字,直接替換掉0 if (((Regex.IsMatch(result, @"^0+") && tb.CaretIndex == 1) || (Regex.IsMatch(result, @"^-0+") && tb.CaretIndex == 2)) && tb.SelectionLength == 0) { if (previewText != ".") { tb.Text = Regex.Replace(tb.Text, @"0+", m => { if (m.Index == 0) { return previewText; } return m.Value; }); tb.CaretIndex = tb.Text.IndexOf(previewText) + 1; e.Handled = true; return; } } //小數點前面不能輸入沒有意義的0 if (Regex.IsMatch(result, @"^-?0(?=\d)")) { e.Handled = true; return; } //小數點後面不能輸沒有意義的0,所以自動補1,1為選中狀態 if (Regex.IsMatch(result, @"\.\d*0$")) { var decimalSpaceLen = Regex.Match(result, @"[^\.]+$").Value.Length; if (decimalSpaceLen <= decimalSpace - 1) { tb.Text = result + "1"; tb.CaretIndex = tb.Text.Length - 1; tb.SelectionStart = tb.CaretIndex; tb.SelectionLength = 1; } e.Handled = true; return; } //如果整數部分只輸入了-號,自動補全為-1 1為選中狀態 if (Regex.IsMatch(result, @"^-(?!\d)")) { tb.Text = result.Replace("-", "-1"); tb.CaretIndex = 1; tb.SelectionStart = 1; tb.SelectionLength = 1; e.Handled = true; return; } //如果在末尾輸入了. ,自動補全為.1 ,1為選中狀態 if (Regex.IsMatch(result, @"\.$")) { var i = result.IndexOf('.'); tb.Text = result.Replace(".", ".1"); tb.CaretIndex = i + 1; tb.SelectionStart = i + 1; tb.SelectionLength = 1; e.Handled = true; return; } //如果輸入了.,但是沒有整數部分,整數部分補0 if (Regex.IsMatch(result, @"^\.")) { tb.Text = "0" + result; tb.CaretIndex = 0; tb.SelectionStart = 0; tb.SelectionLength = 1; e.Handled = true; return; } } } private static string TestFutureText(string previewText, TextBox tb, string deleteMode = null) { var cindex = tb.CaretIndex; var sLen = tb.SelectionLength; var sStartIndex = tb.SelectionStart; var deleteStart = cindex >= sStartIndex ? sStartIndex : cindex; string futureText = string.Empty; //按刪除的 if (!string.IsNullOrEmpty(deleteMode)) { //按刪除鍵,且有選擇字元時,直接刪除選擇的字元 if (tb.SelectionLength > 0) { switch (deleteMode) { case "DeletePreviousWord": case "DeleteNextWord": case "Backspace": case "Delete": default: futureText = tb.Text.Remove(deleteStart, sLen); break; } } //按刪除鍵,沒有選擇字元時 else { switch (deleteMode) { //ctrl+backspace 刪除到 單詞左邊 case "DeletePreviousWord": if (cindex == 0) return tb.Text; var c = tb.Text[cindex - 1]; var isWord = Regex.IsMatch(c.ToString(), @"\w"); if (!isWord) { futureText = tb.Text.Remove(cindex - 1, 1); return futureText; } var startindex = 0; for (int i = 0; i < cindex; i++) { if (Regex.IsMatch(tb.Text[i].ToString(), @"\W")) { startindex = i + 1; } } futureText = tb.Text.Remove(startindex, cindex - startindex); break; //ctrl+delete 刪除到 單詞右邊 case "DeleteNextWord": if (cindex == tb.Text.Length) return tb.Text; var c2 = tb.Text[cindex]; var isWord2 = Regex.IsMatch(c2.ToString(), @"\w"); if (!isWord2) { futureText = tb.Text.Remove(cindex, 1); return futureText; } var end = 0; for (int i = cindex; i < tb.Text.Length; i++) { if (Regex.IsMatch(c2.ToString(), @"\w")) end = i; else break; } futureText = tb.Text.Remove(cindex, end - cindex); break; //刪除游標左邊的字元1個或0個 case "Backspace": futureText = tb.Text.Remove(deleteStart - 1 <= 0 ? 0 : deleteStart - 1, deleteStart >= 1 ? 1 : 0); break; //刪除游標左右的字元1個或0個 case "Delete": futureText = tb.Text.Remove(deleteStart, tb.Text.Length - deleteStart >= 1 ? 1 : 0); break; default: break; } } } //不是按刪除的 else { futureText = tb.Text.Remove(deleteStart, sLen).Insert(deleteStart, previewText); } Console.WriteLine(futureText); return futureText; } private static void Tb_TextChanged(object sender, TextChangedEventArgs e) { var tb = sender as TextBox; var isNumber = GetIsNumber(tb); var isAmount = GetIsAmount(tb); if ((isNumber || isAmount) && string.IsNullOrWhiteSpace(tb.Text)) { tb.Text = "0"; tb.SelectionStart = 0; tb.SelectionLength = 1; } } #endregion } }