Reputation: 466
I was testing the nuances of Data Binding in WPF today, and I came across a strange problem.
In my View, I have
<TextBox Text="{Binding MyInt, UpdateSourceTrigger=LostFocus, StringFormat='{}{##.##}'}"/>
<Label Content="{Binding MyStr2}"/>
In my ViewModel, I have
private decimal myInt;
public decimal MyInt
{
get { return myInt; }
set
{
if (value == myInt) { return; }
myInt = value;
OnPropertyChange();
OnPropertyChange("MyStr2");
}
}
public string MyStr2
{
get
{
return myInt.ToString("N2", CultureInfo.CreateSpecificCulture("en-IN"));
}
}
I want to get the data from the textbox, and format it properly and display it in a label. Simple and easy.
Now, I can only enter decimal data in the textbox, or else the border turns red, indicating an input error.
All is fine when I input decimal data:
But, when I enter garbage data, this happens:
The red border shows there is data input error. But, the label still reflects the older data. I want the label to fall back to 0.00 in case of input error. Is there any way to do that?
I have tried to find a contrived way to do it, and it works, sort of, in an extremely hacky kludgy way.
private string myInt;
private decimal myIntActual;
public string MyInt
{
get
{
return myInt;
}
set
{
if (value == myInt) { return; }
Decimal.TryParse(value.ToString(), out myIntActual);
myInt = myIntActual.ToString();
Decimal.TryParse(myInt, out myIntActual);
OnPropertyChange();
OnPropertyChange("MyStr2");
}
}
public string MyStr2
{
get
{
return myIntActual.ToString("N2", CultureInfo.CreateSpecificCulture("en-IN"));
}
}
What this does is that, it takes the input as a string, tries to parse it to decimal, if it cant, it will return zero. But I have sacrificed the input validation with this code, not to mention that the code looks ugly.
I understand that WPF has a fallback value mechanism when binding fails. Is there any fallback value mechanism in case of input error?
EDIT:
One more thing. After entering the garbage data, the next time I enter valid data, the value somehow reaches the viewmodel, but the textbox becomes blank. And it is a reproducible problem.
Screenshot A:
This is working as is expected.
The garbage data is then entered. Do note that, as the UpdateSourceTrigger
is LostFocus
, the error does not come up until the focus is lost.
I then enter valid data, and...
on losing focus, the textbox blanks out. Do note, that the label is properly updated. I set up breakpoints to see if the binded property is updated or not, and it is, yet the textbox becomes blank. Why is that?
Upvotes: 1
Views: 735
Reputation: 37066
Here's the trigger idea. I tested this and it's working for me. It works with no changes to your viewmodel or code behind.
<TextBox
x:Name="MyIntTextBox"
Text="{Binding MyInt, UpdateSourceTrigger=LostFocus, StringFormat='{}{##.##}'}"
/>
<Label Content="{Binding MyStr2}">
<Label.Style>
<Style TargetType="Label" BasedOn="{StaticResource {x:Type Label}}">
<Style.Triggers>
<!--
parens on (Validation.HasError) are important: It's an attached
so its name has a dot in it. The parens tell the binding that.
-->
<DataTrigger
Binding="{Binding (Validation.HasError), ElementName=MyIntTextBox}"
Value="True">
<Setter
Property="Visibility"
Value="Hidden"
/>
</DataTrigger>
</Style.Triggers>
</Style>
</Label.Style>
</Label>
As for the blank-out behavior, I see that when I type an invalid string into the MyInt box, tab out, tab back in, type a valid value, and tab back out. It only happens when I tab out on a valid value, when the previous value that I tabbed out on was invalid. I think that's exactly the (mis)behavior you're describing.
I don't have an explanation for that. I don't like to run around yelling "bug" on a framework, but I think that's a bug. The control isn't showing the viewmodel property value it's bound to, and the value hasn't changed. I put a breakpoint in the MyInt setter and it only hits the breakpoint once, with the new valid value (aside from the fact that as far as I know there's no integer value that's displayed as an empty string).
I would ask about that as a separate question if google doesn't turn up any workarounds. I tried "wpf textbox invalid tab out empty" and got nothing.
Upvotes: 1