简体   繁体   中英

Notify user if he enters a value into the Textbox which is not allowed in WPF

I'm curious about a good way to notify a user that the value he was trying to enter into a Textbox is not valid. I'd prefer to have a red-flash animation over the textbox to inform the user that the value has been ignored because it's not valid.

However I'm using a Behaviour for my TextBox which gives me the ability to use a regular expression to determine which characters/words are valid and which not.

How or where would I have to modify my code to get this additional feature? I'm not quite sure if this is possible with my Behaviour because invalid input is cancelled before it's entering the TextBox.

Usually I'd check the input in my ViewModel and if it's invalid I'd inform my controller to show an error but because my Behaviour is dealing with this problem I'm not quite sure where to start.

This is my Behaviour:

public class AllowableCharactersTextBoxBehavior : Behavior<TextBox>
{
    public static readonly DependencyProperty RegularExpressionProperty =
        DependencyProperty.Register("RegularExpression", typeof (string),
                                    typeof (AllowableCharactersTextBoxBehavior),
                                    new FrameworkPropertyMetadata("*"));

    public string RegularExpression
    {
        get { return (string) base.GetValue(RegularExpressionProperty); }
        set { base.SetValue(RegularExpressionProperty, value); }
    }

    public static readonly DependencyProperty MaxLengthProperty =
        DependencyProperty.Register("MaxLength", typeof (int), typeof (AllowableCharactersTextBoxBehavior),
                                    new FrameworkPropertyMetadata(int.MinValue));

    public int MaxLength
    {
        get { return (int) base.GetValue(MaxLengthProperty); }
        set { base.SetValue(MaxLengthProperty, value); }
    }

    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.PreviewTextInput += OnPreviewTextInput;
        DataObject.AddPastingHandler(AssociatedObject, OnPaste);
    }

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

            if (!IsValid(text, true))
            {
                e.CancelCommand();
            }
        }
        else
        {
            e.CancelCommand();
        }
    }

    private void OnPreviewTextInput(object sender, System.Windows.Input.TextCompositionEventArgs e)
    {
        e.Handled = !IsValid(e.Text, false);
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();
        AssociatedObject.PreviewTextInput -= OnPreviewTextInput;
        DataObject.RemovePastingHandler(AssociatedObject, OnPaste);
    }

    private bool IsValid(string newText, bool paste)
    {
        return !ExceedsMaxLength(newText, paste) && Regex.IsMatch(newText, RegularExpression);
    }

    private bool ExceedsMaxLength(string newText, bool paste)
    {
        if (MaxLength == 0) return false;

        return LengthOfModifiedText(newText, paste) > MaxLength;
    }

    private int LengthOfModifiedText(string newText, bool paste)
    {
        var countOfSelectedChars = this.AssociatedObject.SelectedText.Length;
        var caretIndex = this.AssociatedObject.CaretIndex;
        string text = this.AssociatedObject.Text;

        if (countOfSelectedChars > 0 || paste)
        {
            text = text.Remove(caretIndex, countOfSelectedChars);
            return text.Length + newText.Length;
        }
        else
        {
            var insert = Keyboard.IsKeyToggled(Key.Insert);

            return insert && caretIndex < text.Length ? text.Length : text.Length + newText.Length;
        }
    }
}

I think I would have to modify the code in the OnPreviewTextInput Method to signalize that the input was wrong. But how do I add a flash animation or something else to it?

For styling your Validation.ErrorTemplate look at this SO answer for some ideas.

For setting your control in an invalid state you can use (assuming you have bound the TextProperty to your viewmodel)

    private void OnPreviewTextInput(object sender, System.Windows.Input.TextCompositionEventArgs e)
    {
        e.Handled = !IsValid(e.Text, false);
        if(e.Handled)
        {
            var be = BindingOperations.GetBindingExpression(AssociatedObject, TextBox.TextProperty);
            Validation.MarkInvalid(be, new ValidationError(new DummyValidationRule(), be.ParentBinding));
        }
    }

    private class DummyValidationRule : ValidationRule
    {

        public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
        {
            return new ValidationResult(false, "ErrorMessage");
        }
    }

Considered to use the build-in mechanisms of wpf? Here is a blog post from Magnus Montin with a lot of information about validation in wpf.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM