Michael A
Michael A

Reputation: 9930

Curious bug with TextChanged event (WPF Textbox)

I have a textbox that I'm trying to limit in two ways:

1 - I only want to allow numeric values, no decimals

2 - I only want to accept numbers that are <= 35

I have the following events to handle this:

private void TextBoxWorkflowCountPreviewTextInput(object sender, TextCompositionEventArgs e)
{
    if (!IsNumeric(e.Text, NumberStyles.Integer)) e.Handled = true;
}

public bool IsNumeric(string val, NumberStyles numberStyle)
{
    double result;
    return double.TryParse(val, numberStyle, CultureInfo.CurrentCulture, out result);
}

private void TextBoxWorkflowCountTextChanged(object sender, TextChangedEventArgs e)
{
    if (!string.IsNullOrEmpty(textBoxWorkflowCount.Text) && Convert.ToInt32(textBoxWorkflowCount.Text) <= 35) e.Handled = true;
    else
    {
        MessageBox.Show("Must not be higher then 35");
        textBoxWorkflowCount.Text = "35";
    }
}

This on the surface works perfectly fine - except when the user either pastes data into the textbox (appears unavoidable) or even more curiously - if the user enters a number and then hits backspace (making the textbox blank again) the messagebox letting the user know that their value is >35 appears (even though that is definitely not the case). The first issue I can live with if I have to - but the second is game breaking and after 30 minutes of trying to solve it I've got nowhere. Help!

Upvotes: 0

Views: 1463

Answers (2)

outcoldman
outcoldman

Reputation: 11832

couple months ago I wrote a blog post about Behaviors for TextBox (Windows Phone 7.5 platform), and one of these bahaviors was the TextBoxInputRegexFilterBehavior, which allows you to filter input text. So if you are familar with how Behaviors work you can use this code

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

/// <summary>
/// UI behavior for <see cref="TextBox"/> to filter input text with special RegularExpression.
/// </summary>
public class TextBoxInputRegexFilterBehavior : Behavior<TextBox>
{
    private Regex regex;

    private string originalText;
    private int originalSelectionStart;
    private int originalSelectionLength;

    /// <summary>
    /// Gets or sets RegularExpression.
    /// </summary>
    public string RegularExpression 
    {
        get
        {
            return this.regex.ToString();
        } 

        set 
        {
            if (string.IsNullOrEmpty(value))
            {
                this.regex = null;
            }
            else
            {
                this.regex = new Regex(value);
            }
        } 
    }

    /// <inheritdoc/>
    protected override void OnAttached()
    {
        base.OnAttached();

        this.AssociatedObject.TextInputStart += this.AssociatedObjectTextInputStart;
        this.AssociatedObject.TextChanged += this.AssociatedObjectTextChanged;
    }

    /// <inheritdoc/>
    protected override void OnDetaching()
    {
        base.OnDetaching();

        this.AssociatedObject.TextInputStart -= this.AssociatedObjectTextInputStart;
        this.AssociatedObject.TextChanged -= this.AssociatedObjectTextChanged;
    }

    private void AssociatedObjectTextChanged(object sender, TextChangedEventArgs e)
    {
        if (this.originalText != null)
        {
            string text = this.originalText;
            this.originalText = null;
            this.AssociatedObject.Text = text;
            this.AssociatedObject.Select(this.originalSelectionStart, this.originalSelectionLength);
        }
    }

    private void AssociatedObjectTextInputStart(object sender, TextCompositionEventArgs e)
    {
        if (this.regex != null && e.Text != null && !(e.Text.Length == 1 && char.IsControl(e.Text[0])))
        {
            if (!this.regex.IsMatch(e.Text))
            {
                this.originalText = this.AssociatedObject.Text;
                this.originalSelectionStart = this.AssociatedObject.SelectionStart;
                this.originalSelectionLength = this.AssociatedObject.SelectionLength;
            }
        }
    }
}

So, with this behavior you can write simple regex expression which will filter user input, like this RegularExpression="(3[0-5])|([0-2]?[0-9])"

Upvotes: 1

FJT
FJT

Reputation: 2083

Your code is failing the first condition because

string.IsNullOrEmpty(textBoxWorkflowCount.Text) 

evaluates to true, so it's falling through to the 'else', and displaying the message.

if (string.IsNullOrEmpty(textBoxWorkflowCount.Text) || Convert.ToInt32(textBoxWorkflowCount.Text) <= 35) e.Handled = true; 

should do the trick

Upvotes: 1

Related Questions