C# WPF文本框输入过滤不';如果使用十进制,则无法按预期工作

C# WPF文本框输入过滤不';如果使用十进制,则无法按预期工作,c#,wpf,validation,input,textbox,C#,Wpf,Validation,Input,Textbox,我试图过滤WPF文本框的输入,以防止用户输入非数字字符串。我已经配置了PreviewKeyDown,正在检查与代码一起输入的字符,以便将键代码转换为字符。除用户输入时段外,所有操作都按预期进行。代码确实检测到输入了一个期间,但是当我从PreviewKeyDown返回并将KeyEventArgs的Handled设置为false时,它不允许输入期间 XAML <TextBox PreviewKeyDown="TextBox_PreviewKeyDown"> <TextBox

我试图过滤WPF
文本框的输入,以防止用户输入非数字字符串。我已经配置了
PreviewKeyDown
,正在检查与代码一起输入的字符,以便将键代码转换为字符。除用户输入时段外,所有操作都按预期进行。代码确实检测到输入了一个期间,但是当我从
PreviewKeyDown
返回并将
KeyEventArgs
Handled
设置为false时,它不允许输入期间

XAML

<TextBox PreviewKeyDown="TextBox_PreviewKeyDown">
    <TextBox.Text>
        <Binding Source="{StaticResource SomeObject}" Path="SomePath" UpdateSourceTrigger="PropertyChanged">
            <Binding.ValidationRules>
                <local:MyValidationRule/>
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>
</TextBox>

C#

private void TextBox\u PreviewKeyDown(对象发送方,KeyEventArgs e)
{
char character=GetCharFromKey(e.Key);
e、 已处理=错误;

如果(character>='0'&&character我有一个用于此的行为,我认为它是基于我从web上获得的内容。您可以按原样使用它,或者找出您的版本不起作用的原因。请注意,代码处理粘贴

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interactivity;

namespace UILib
{
    public class TextBoxDecimalRangeBehaviour : Behavior<TextBox>
    {
        public string EmptyValue { get; set; } = "0";

        public double Minimum
        {
            get { return (double)GetValue(MinimumProperty); }
            set { SetValue(MinimumProperty, value); }
        }
        public static readonly DependencyProperty MinimumProperty =
            DependencyProperty.Register("Minimum", typeof(double), typeof(TextBoxDecimalRangeBehaviour), new PropertyMetadata(0.0));


        public double Maximum
        {
            get { return (double)GetValue(MaximumProperty); }
            set { SetValue(MaximumProperty, value); }
        }
        public static readonly DependencyProperty MaximumProperty =
            DependencyProperty.Register("Maximum", typeof(double), typeof(TextBoxDecimalRangeBehaviour), new PropertyMetadata(10.0));



        public int MaxInteger
        {
            get { return (int)GetValue(MaxIntegerProperty); }
            set { SetValue(MaxIntegerProperty, value); }
        }
        public static readonly DependencyProperty MaxIntegerProperty =
            DependencyProperty.Register("MaxInteger", typeof(int), typeof(TextBoxDecimalRangeBehaviour), new PropertyMetadata(1));



        public int MaxDecimals
        {
            get { return (int)GetValue(MaxDecimalsProperty); }
            set { SetValue(MaxDecimalsProperty, value); }
        }

        public static readonly DependencyProperty MaxDecimalsProperty =
            DependencyProperty.Register("MaxDecimals", typeof(int), typeof(TextBoxDecimalRangeBehaviour), new PropertyMetadata(2));



        /// <summary>
        ///     Attach our behaviour. Add event handlers
        /// </summary>
        protected override void OnAttached()
        {
            base.OnAttached();

            AssociatedObject.PreviewTextInput += PreviewTextInputHandler;
            AssociatedObject.PreviewKeyDown += PreviewKeyDownHandler;
            DataObject.AddPastingHandler(AssociatedObject, PastingHandler);
        }

        /// <summary>
        ///     Deattach our behaviour. remove event handlers
        /// </summary>
        protected override void OnDetaching()
        {
            base.OnDetaching();

            AssociatedObject.PreviewTextInput -= PreviewTextInputHandler;
            AssociatedObject.PreviewKeyDown -= PreviewKeyDownHandler;
            DataObject.RemovePastingHandler(AssociatedObject, PastingHandler);
        }

        void PreviewTextInputHandler(object sender, TextCompositionEventArgs e)
        {
            string text;
            if (this.AssociatedObject.Text.Length < this.AssociatedObject.CaretIndex)
                text = this.AssociatedObject.Text;
            else
            {
                //  Remaining text after removing selected text.
                string remainingTextAfterRemoveSelection;

                text = TreatSelectedText(out remainingTextAfterRemoveSelection)
                    ? remainingTextAfterRemoveSelection.Insert(AssociatedObject.SelectionStart, e.Text)
                    : AssociatedObject.Text.Insert(this.AssociatedObject.CaretIndex, e.Text);
            }

            e.Handled = !ValidateText(text);
        }

        /// <summary>
        ///     PreviewKeyDown event handler
        /// </summary>
        void PreviewKeyDownHandler(object sender, KeyEventArgs e)
        {
            if (string.IsNullOrEmpty(this.EmptyValue))
            {
                return;
            }


            string text = null;

            // Handle the Backspace key
            if (e.Key == Key.Back)
            {
                if (!this.TreatSelectedText(out text))
                {
                    if (AssociatedObject.SelectionStart > 0)
                        text = this.AssociatedObject.Text.Remove(AssociatedObject.SelectionStart - 1, 1);
                }
            }
            // Handle the Delete key
            else if (e.Key == Key.Delete)
            {
                // If text was selected, delete it
                if (!this.TreatSelectedText(out text) && this.AssociatedObject.Text.Length > AssociatedObject.SelectionStart)
                {
                    // Otherwise delete next symbol
                    text = this.AssociatedObject.Text.Remove(AssociatedObject.SelectionStart, 1);
                }
            }

            if (text == string.Empty)
            {
                this.AssociatedObject.Text = this.EmptyValue;
                if (e.Key == Key.Back)
                    AssociatedObject.SelectionStart++;
                e.Handled = true;
            }
        }

        private void PastingHandler(object sender, DataObjectPastingEventArgs e)
        {
            if (e.DataObject.GetDataPresent(DataFormats.Text))
            {
                string text = Convert.ToString(e.DataObject.GetData(DataFormats.Text));

                if (!ValidateText(text))
                    e.CancelCommand();
            }
            else
                e.CancelCommand();
        }

        /// <summary>
        ///     Validate certain text by our regular expression and text length conditions
        /// </summary>
        /// <param name="text"> Text for validation </param>
        /// <returns> True - valid, False - invalid </returns>
        private bool ValidateText(string text)
        {
            double number;
            if (!Double.TryParse(text, out number))
            {
                return false;
            }
            if(number < Minimum)
            {
                return false;
            }
            if (number > Maximum)
            {
                return false;
            }
            int dotPointer = text.IndexOf('.');
            // No point entered so the decimals must be ok
            if(dotPointer == -1)
            {
                return true;
            }
            if (dotPointer > MaxInteger)
            {
                return false;
            }
            if(text.Substring(dotPointer +1).Length > MaxDecimals)
            {
                return false;
            }
            return true;
        }

        /// <summary>
        ///     Handle text selection
        /// </summary>
        /// <returns>true if the character was successfully removed; otherwise, false. </returns>
        private bool TreatSelectedText(out string text)
        {
            text = null;
            if (AssociatedObject.SelectionLength <= 0)
                return false;

            var length = this.AssociatedObject.Text.Length;
            if (AssociatedObject.SelectionStart >= length)
                return true;

            if (AssociatedObject.SelectionStart + AssociatedObject.SelectionLength >= length)
                AssociatedObject.SelectionLength = length - AssociatedObject.SelectionStart;

            text = this.AssociatedObject.Text.Remove(AssociatedObject.SelectionStart, AssociatedObject.SelectionLength);
            return true;
        }
    }
}
使用系统;
使用System.Windows;
使用System.Windows.Controls;
使用System.Windows.Input;
使用System.Windows.Interactive;
命名空间UILib
{
公共类TextBoxDecimalRangeBehavior:行为
{
公共字符串EmptyValue{get;set;}=“0”;
公共双最小值
{
获取{return(double)GetValue(MinimumProperty);}
set{SetValue(MinimumProperty,value);}
}
公共静态只读从属属性MinimumProperty=
DependencyProperty.Register(“最小”、typeof(双精度)、typeof(TextBoxDecimalRangeBehavior)、new PropertyMetadata(0.0));
公共双倍最大值
{
获取{return(double)GetValue(MaximumProperty);}
set{SetValue(MaximumProperty,value);}
}
公共静态只读从属属性MaximumProperty=
DependencyProperty.Register(“最大值”、typeof(双精度)、typeof(TextBoxDecimalRangeBehavior)、new PropertyMetadata(10.0));
公共整数MaxInteger
{
获取{return(int)GetValue(MaxIntegerProperty);}
set{SetValue(MaxIntegerProperty,value);}
}
公共静态只读从属属性MaxIntegerProperty=
DependencyProperty.Register(“MaxInteger”、typeof(int)、typeof(TextBoxDecimalRangeBehavior)、new PropertyMetadata(1));
公共整数最大小数
{
get{return(int)GetValue(MaxDecimalsProperty);}
set{SetValue(MaxDecimalsProperty,value);}
}
公共静态只读从属属性MaxDecimalsProperty=
DependencyProperty.Register(“MaxDecimals”、typeof(int)、typeof(TextBoxDecimalRangeBehavior)、new PropertyMetadata(2));
/// 
///附加我们的行为。添加事件处理程序
/// 
受保护的覆盖无效附加()
{
base.onatached();
AssociatedObject.PreviewTestInput+=PreviewTestInputHandler;
AssociatedObject.PreviewKeyDown+=PreviewKeyDownHandler;
AddPastingHandler(AssociatedObject,PastingHandler);
}
/// 
///删除我们的行为。删除事件处理程序
/// 
附加时受保护的覆盖无效()
{
base.OnDetaching();
AssociatedObject.PreviewTestInput-=PreviewTestInputHandler;
AssociatedObject.PreviewKeyDown-=PreviewKeyDownHandler;
RemovePastingHandler(AssociatedObject,PastingHandler);
}
void PreviewTemputePutHandler(对象发送者,TextCompositionEventArgs e)
{
字符串文本;
if(this.AssociatedObject.Text.Length0)
text=this.AssociatedObject.text.Remove(AssociatedObject.SelectionStart-1,1);
}
}
//处理删除键
else if(e.Key==Key.Delete)
{
//如果选择了文本,请将其删除
如果(!this.TreatSelectedText(out text)&&this.AssociatedObject.text.Length>AssociatedObject.SelectionStart)
{
//否则删除下一个符号
text=this.AssociatedObject.text.Remove(AssociatedObject.SelectionStart,1);
}
}
if(text==string.Empty)
{
this.AssociatedObject.Text=this.EmptyValue;
if(e.Key==Key.Back)
AssociatedObject.SelectionStart++;
e、 已处理=正确;
}
}
私有void粘贴处理程序(对象发送方、DataObjectPastingEventArgs e)
{
if(例如DataObject.GetDataPresent(DataFormats.Text
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interactivity;

namespace UILib
{
    public class TextBoxDecimalRangeBehaviour : Behavior<TextBox>
    {
        public string EmptyValue { get; set; } = "0";

        public double Minimum
        {
            get { return (double)GetValue(MinimumProperty); }
            set { SetValue(MinimumProperty, value); }
        }
        public static readonly DependencyProperty MinimumProperty =
            DependencyProperty.Register("Minimum", typeof(double), typeof(TextBoxDecimalRangeBehaviour), new PropertyMetadata(0.0));


        public double Maximum
        {
            get { return (double)GetValue(MaximumProperty); }
            set { SetValue(MaximumProperty, value); }
        }
        public static readonly DependencyProperty MaximumProperty =
            DependencyProperty.Register("Maximum", typeof(double), typeof(TextBoxDecimalRangeBehaviour), new PropertyMetadata(10.0));



        public int MaxInteger
        {
            get { return (int)GetValue(MaxIntegerProperty); }
            set { SetValue(MaxIntegerProperty, value); }
        }
        public static readonly DependencyProperty MaxIntegerProperty =
            DependencyProperty.Register("MaxInteger", typeof(int), typeof(TextBoxDecimalRangeBehaviour), new PropertyMetadata(1));



        public int MaxDecimals
        {
            get { return (int)GetValue(MaxDecimalsProperty); }
            set { SetValue(MaxDecimalsProperty, value); }
        }

        public static readonly DependencyProperty MaxDecimalsProperty =
            DependencyProperty.Register("MaxDecimals", typeof(int), typeof(TextBoxDecimalRangeBehaviour), new PropertyMetadata(2));



        /// <summary>
        ///     Attach our behaviour. Add event handlers
        /// </summary>
        protected override void OnAttached()
        {
            base.OnAttached();

            AssociatedObject.PreviewTextInput += PreviewTextInputHandler;
            AssociatedObject.PreviewKeyDown += PreviewKeyDownHandler;
            DataObject.AddPastingHandler(AssociatedObject, PastingHandler);
        }

        /// <summary>
        ///     Deattach our behaviour. remove event handlers
        /// </summary>
        protected override void OnDetaching()
        {
            base.OnDetaching();

            AssociatedObject.PreviewTextInput -= PreviewTextInputHandler;
            AssociatedObject.PreviewKeyDown -= PreviewKeyDownHandler;
            DataObject.RemovePastingHandler(AssociatedObject, PastingHandler);
        }

        void PreviewTextInputHandler(object sender, TextCompositionEventArgs e)
        {
            string text;
            if (this.AssociatedObject.Text.Length < this.AssociatedObject.CaretIndex)
                text = this.AssociatedObject.Text;
            else
            {
                //  Remaining text after removing selected text.
                string remainingTextAfterRemoveSelection;

                text = TreatSelectedText(out remainingTextAfterRemoveSelection)
                    ? remainingTextAfterRemoveSelection.Insert(AssociatedObject.SelectionStart, e.Text)
                    : AssociatedObject.Text.Insert(this.AssociatedObject.CaretIndex, e.Text);
            }

            e.Handled = !ValidateText(text);
        }

        /// <summary>
        ///     PreviewKeyDown event handler
        /// </summary>
        void PreviewKeyDownHandler(object sender, KeyEventArgs e)
        {
            if (string.IsNullOrEmpty(this.EmptyValue))
            {
                return;
            }


            string text = null;

            // Handle the Backspace key
            if (e.Key == Key.Back)
            {
                if (!this.TreatSelectedText(out text))
                {
                    if (AssociatedObject.SelectionStart > 0)
                        text = this.AssociatedObject.Text.Remove(AssociatedObject.SelectionStart - 1, 1);
                }
            }
            // Handle the Delete key
            else if (e.Key == Key.Delete)
            {
                // If text was selected, delete it
                if (!this.TreatSelectedText(out text) && this.AssociatedObject.Text.Length > AssociatedObject.SelectionStart)
                {
                    // Otherwise delete next symbol
                    text = this.AssociatedObject.Text.Remove(AssociatedObject.SelectionStart, 1);
                }
            }

            if (text == string.Empty)
            {
                this.AssociatedObject.Text = this.EmptyValue;
                if (e.Key == Key.Back)
                    AssociatedObject.SelectionStart++;
                e.Handled = true;
            }
        }

        private void PastingHandler(object sender, DataObjectPastingEventArgs e)
        {
            if (e.DataObject.GetDataPresent(DataFormats.Text))
            {
                string text = Convert.ToString(e.DataObject.GetData(DataFormats.Text));

                if (!ValidateText(text))
                    e.CancelCommand();
            }
            else
                e.CancelCommand();
        }

        /// <summary>
        ///     Validate certain text by our regular expression and text length conditions
        /// </summary>
        /// <param name="text"> Text for validation </param>
        /// <returns> True - valid, False - invalid </returns>
        private bool ValidateText(string text)
        {
            double number;
            if (!Double.TryParse(text, out number))
            {
                return false;
            }
            if(number < Minimum)
            {
                return false;
            }
            if (number > Maximum)
            {
                return false;
            }
            int dotPointer = text.IndexOf('.');
            // No point entered so the decimals must be ok
            if(dotPointer == -1)
            {
                return true;
            }
            if (dotPointer > MaxInteger)
            {
                return false;
            }
            if(text.Substring(dotPointer +1).Length > MaxDecimals)
            {
                return false;
            }
            return true;
        }

        /// <summary>
        ///     Handle text selection
        /// </summary>
        /// <returns>true if the character was successfully removed; otherwise, false. </returns>
        private bool TreatSelectedText(out string text)
        {
            text = null;
            if (AssociatedObject.SelectionLength <= 0)
                return false;

            var length = this.AssociatedObject.Text.Length;
            if (AssociatedObject.SelectionStart >= length)
                return true;

            if (AssociatedObject.SelectionStart + AssociatedObject.SelectionLength >= length)
                AssociatedObject.SelectionLength = length - AssociatedObject.SelectionStart;

            text = this.AssociatedObject.Text.Remove(AssociatedObject.SelectionStart, AssociatedObject.SelectionLength);
            return true;
        }
    }
}
<TextBox Text="{Binding ......>
    <i:Interaction.Behaviors>
        <ui:TextBoxDecimalRangeBehaviour MaxDecimals="2" 
                                         MaxInteger="1" 
                                         Minimum="{StaticResource Zero}" 
                                         Maximum="{StaticResource Ten}" />
        <ui:SelectAllTextBoxBehavior/>
    </i:Interaction.Behaviors>
</TextBox>
private void TextBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
    string str = ((TextBox)sender).Text + e.Text;
    decimal i;
    e.Handled = !decimal.TryParse(str, System.Globalization.NumberStyles.AllowDecimalPoint, System.Globalization.CultureInfo.InvariantCulture, out i);
}
<TextBox Text="{Binding SomePath}" PreviewTextInput="TextBox_PreviewTextInput" />
public class DecimalToStringConverter : IValueConverter
{
    private string _lastConvertedValue;

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return _lastConvertedValue ?? value;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        string str = value?.ToString();
        decimal d;
        if (decimal.TryParse(str, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out d))
        {
            _lastConvertedValue = str;
            return d;
        }

        _lastConvertedValue = null;
        return Binding.DoNothing;
    }
}
<TextBox PreviewTextInput="TextBox_PreviewTextInput">
    <TextBox.Text>
        <Binding Path="SomePath" UpdateSourceTrigger="PropertyChanged">
            <Binding.Converter>
                <local:DecimalToStringConverter />
            </Binding.Converter>
        </Binding>
    </TextBox.Text>
</TextBox>