Reputation: 731
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?
Upvotes: 5
Views: 2638
Reputation: 3589
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);
Upvotes: 4
Reputation: 43046
I would use the framework's binding validation system (see How to Implement Binding Validation).
When a user types something invalid, it may well be better to leave the invalid input in the control, so the user can edit it to something valid. That's more user-friendly than forcing them to re-enter the data from scratch.
For example, if the value was 0.0, and the user types "4.252w35326", should we force the user to type "4.25235326" again, rather than simply deleting the "w"?
Upvotes: 2