Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I make a validating TextBox with Binding in WPF that switches back to the last valid value after invalid entry?

In WPF, I want to make a TextBox that validates user input to only allow input that parses to a double. When the box loses focus (and the Binding updates), if the user had entered invalid input, I want the box to switch back to what it had before.

This seems like it should be simple, but I can't get it to work. No matter what I've tried, the TextBox continues to display the invalid string the user entered even though the property is properly validating the input and not saving unless valid. I feel like notifying property changed on a failed parse should cause the TextBox to reset to the old value, but it doesn't.

My view model has a property:

private double _doubleDisplayValue;
public string DoubleDisplayValue
{
    get { return _doubleDisplayValue.ToString(); }
    set
    {
        double result;
        bool success = double.TryParse(value, out result);
        if(success)
        {
            if(_doubleDisplayValue != result)
            {
                _doubleDisplayValue = result;
                NotifyPropertyChanged("DoubleDisplayValue");
            }
        }
        else
        {
            // I feel like notifying property changed here should make the TextBox
            // update back to the old value (still in the backing variable), but
            // it just keeps whatever invalid string the user entered.
            NotifyPropertyChanged("DoubleDisplayValue");
        }
    }   
}

And I set up my TextBox (I'm working in code behind):

// . . .
TextBox textBox = new TextBox();
Binding b = new Binding("DoubleDisplayValue");
b.Mode = BindingMode.TwoWay;
// assume the DataContext is properly set so the Binding has the right source
textBox.SetBinding(TextBox.TextProperty, b);
// . . .

I've also tried modifying the property to this, but it still doesn't work:

private double _doubleDisplayValue;
public string DoubleDisplayValue
{
    get { return _doubleDisplayValue.ToString(); }
    set
    {
        double result;
        bool success = double.TryParse(value, out result);
        if(success)
        {
            // got rid of the if
            _doubleDisplayValue = result;
            NotifyPropertyChanged("DoubleDisplayValue");                
        }
        else
        {
            // Figured maybe I need to retrigger the setter
            DoubleDisplayValue = _doubleDisplayValue;
        }
    }   
}

What's the best way to accomplish my goal?

like image 407
axanpi Avatar asked Apr 04 '12 15:04

axanpi


People also ask

How do you implement binding validation?

As shown in the following example, the ToolTip that shows the error message is created using the style named textBoxInError . If the value of HasError is true , the trigger sets the tool tip of the current TextBox to its first validation error. The RelativeSource is set to Self, referring to the current element.

What is Updateourcetrigger WPF?

The UpdateSourceTrigger property of a binding controls how and when a changed value is sent back to the source. However, since WPF is pretty good at controlling this for you, the default value should suffice for most cases, where you will get the best mix of a constantly updated UI and good performance.


1 Answers

If you really want to reset the value displayed in the TextBox you have to do something along the following lines in DoubleDisplayValue's setter else:

Application.Current.Dispatcher.BeginInvoke(new Action(() =>
    {
        _doubleDisplayValue = originalValue;
        NotifyPropertyChanged("DoubleDisplayValue");
    }), DispatcherPriority.ContextIdle, null);
like image 134
Scroog1 Avatar answered Nov 05 '22 15:11

Scroog1