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?
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.
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.
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);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With