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

binding, c#, mvvm, validation, wpf

Solution

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);

Problem

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?

Original source

Related problems