此类为TextBox的一个扩展类,其中包含四个附加属性,分别是:

属性 IntegerRange Minimum Maximum PreviousValue
类型 bool int int string
定义 是否启用范围判定 最小值 最大值 前一个有效值
默认值 false 0 int的最大值

实现了以下功能:

  • 若输入的值不满足最小值和最大值的范围或输入不合法时,则会自动恢复为前一个有效值
  • 解决了粘贴时的输入验证问题
  • 解决了用户选中文本后输入的问题
  • 解决了当最小值大于9时,无法输入数字的问题

源代码:

public static class TextBoxExtensions
    {
        #region IntegerRange

        public static readonly DependencyProperty IntegerRangeProperty =
            DependencyProperty.RegisterAttached(
                "IntegerRange",
                typeof(bool),
                typeof(TextBoxExtensions),
                new PropertyMetadata(false, OnIntegerRangeChanged));

        public static bool GetIntegerRange(DependencyObject target)
        {
            return (bool)target.GetValue(IntegerRangeProperty);
        }

        public static void SetIntegerRange(DependencyObject target, bool value)
        {
            target.SetValue(IntegerRangeProperty, value);
        }

        #endregion

        #region Minimum
        public static readonly DependencyProperty MinimumProperty =
            DependencyProperty.RegisterAttached(
                "Minimum",
                typeof(int),
                typeof(TextBoxExtensions),
                new PropertyMetadata(0));

        public static int GetMinimum(DependencyObject target)
        {
            return (int)target.GetValue(MinimumProperty);
        }

        public static void SetMinimum(DependencyObject target, int value)
        {
            target.SetValue(MinimumProperty, value);
        }
        #endregion

        #region Maximum
        public static readonly DependencyProperty MaximumProperty =
            DependencyProperty.RegisterAttached(
                "Maximum",
                typeof(int),
                typeof(TextBoxExtensions),
                new PropertyMetadata(int.MaxValue));

        public static int GetMaximum(DependencyObject target)
        {
            return (int)target.GetValue(MaximumProperty);
        }

        public static void SetMaximum(DependencyObject target, int value)
        {
            target.SetValue(MaximumProperty, value);
        }
        #endregion

        #region PreviousValue

        public static readonly DependencyProperty PreviousValueProperty =
            DependencyProperty.RegisterAttached("PreviousValue", typeof(string), typeof(TextBoxExtensions));

        public static string GetPreviousValue(DependencyObject obj)
        {
            return (string)obj.GetValue(PreviousValueProperty);
        }

        public static void SetPreviousValue(DependencyObject obj, string value)
        {
            obj.SetValue(PreviousValueProperty, value);
        }


        #endregion
        private static void OnIntegerRangeChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            TextBox textBox = sender as TextBox;
            if (textBox != null)
            {
                if ((bool)e.NewValue)
                {
                    textBox.PreviewTextInput += TextBox_PreviewTextInput;
                    DataObject.AddPastingHandler(textBox, TextBox_Pasting);
                    textBox.LostFocus += TextBox_LostFocus;
                }
                else
                {
                    textBox.PreviewTextInput -= TextBox_PreviewTextInput;
                    DataObject.RemovePastingHandler(textBox, TextBox_Pasting);
                    textBox.LostFocus -= TextBox_LostFocus;
                }
            }
        }

        private static void TextBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
        {
            TextBox textBox = (TextBox)sender;
            string fullText = textBox.SelectionLength > 0
                ? textBox.Text.Remove(textBox.SelectionStart, textBox.SelectionLength).Insert(textBox.SelectionStart, e.Text)
                : textBox.Text.Insert(textBox.SelectionStart, e.Text);
            int value;
            int maximum = GetMaximum(textBox);
            if (!int.TryParse(fullText, out value) || value > maximum)
            {
                e.Handled = true;
            }
            else
            {
                // If the text is valid, update the PreviousValue property
                SetPreviousValue(textBox, textBox.Text);
            }
        }

        private static void TextBox_LostFocus(object sender, RoutedEventArgs e)
        {
            TextBox textBox = (TextBox)sender;
            double minimum = GetMinimum(textBox);
            double maximum = GetMaximum(textBox);
            if (double.TryParse(textBox.Text, out var value) && (value < minimum || value > maximum ))
            {
                textBox.Text = GetPreviousValue(textBox);
            }
        }

        private static void TextBox_Pasting(object sender, DataObjectPastingEventArgs e)
        {
            TextBox textBox = (TextBox)sender;
            string pasteText = e.DataObject.GetData(typeof(string)) as string;
            string fullText = textBox.SelectionLength > 0
                ? textBox.Text.Remove(textBox.SelectionStart, textBox.SelectionLength).Insert(textBox.SelectionStart, pasteText)
                : textBox.Text.Insert(textBox.SelectionStart, pasteText);
            int value;
            int minimum = GetMinimum(textBox);
            int maximum = GetMaximum(textBox);
            if (!int.TryParse(fullText, out value) || value < minimum || value > maximum)
            {
                e.CancelCommand();
            }
        }
    }