1. 程式人生 > 其它 >備份一段程式碼,用於提前測試textbox輸入字元後的字串

備份一段程式碼,用於提前測試textbox輸入字元後的字串

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


    }
}