Reputation: 466
So, I have a simple view containing a Textbox and a Label.
<TextBox x:Name="MyIntTextBox" Text="{Binding MyInt, UpdateSourceTrigger=LostFocus, Mode=TwoWay, StringFormat={}{D2}}"/>
<Label Content="{Binding MyStr2}"/>
And in the 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"));
}
}
Simply speaking, the TextBox
Text
is bound to a decimal
value, and the Label
is supposed display the value in the textbox
with proper formatting.
Since I have LostFocus
as my UpdateSourceTrigger
in TextBox
, I press TAB
in order for the validation
and binding
to work.
So when I enter a decimal
value, everything works properly. The Label
properly displays the formatted number.
And when I enter some garbage non-decimal value, the TextBox
Border
turns red indicating validation error.
But, when I put some valid value after that, like this...
...and then focus out of the TextBox
, bam! The TextBox
goes blank.
The Label
however indicates the correct value. I set up breakpoints in the ViewModel
, and I can see that MyInt
does have the correct value, in this case, 600, but the TextBox
does not display it.
I also get the following error in my Output
Window:
System.Windows.Data Error: 6 : 'StringFormat' converter failed to convert value '600' (type 'Decimal'); fallback value will be used, if available. BindingExpression:Path=MyInt; DataItem='ViewModel' (HashCode=37975124); target element is 'TextBox' (Name='MyIntTextBox'); target property is 'Text' (type 'String') FormatException:'System.FormatException: Input string was not in a correct format.
at System.Text.StringBuilder.AppendFormatHelper(IFormatProvider provider, String format, ParamsArray args)
at System.String.FormatHelper(IFormatProvider provider, String format, ParamsArray args)
at System.String.Format(IFormatProvider provider, String format, Object[] args)
at System.Windows.Data.BindingExpression.ConvertHelper(IValueConverter converter, Object value, Type targetType, Object parameter, CultureInfo culture)'
Is there any simple workaround for this? Or is it something I am doing wrong?
Upvotes: 1
Views: 500
Reputation: 1934
The solution of mm8 is good but fails with nullable decimals. Here is a fixed ConvertBack function:
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (decimal.TryParse(value.ToString(), out var d))
return d;
if (Nullable.GetUnderlyingType(targetType) != null)
return null;
else
return 0m;
}
Upvotes: 0
Reputation: 169210
But, when I put some valid value after that, like this...
It will work again if you type in a decimal
value into the TextBox
.
But the workaround would otherwise be to implement your own custom converter class that handles the conversion between decimal
and string
.
Try this:
namespace WpfApp2
{
class DecimalToStringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null)
return null;
return System.Convert.ToDecimal(value).ToString(parameter as string);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
decimal d;
if (decimal.TryParse(value.ToString(), out d))
return d;
return value;
}
}
}
<StackPanel xmlns:local="clr-namespace:WpfApp2">
<StackPanel.Resources>
<local:DecimalToStringConverter x:Key="conv" />
</StackPanel.Resources>
<TextBox x:Name="MyIntTextBox" Text="{Binding MyInt, Converter={StaticResource conv}, ConverterParameter=0.00}"/>
<Label Content="{Binding MyStr2}"/>
</StackPanel>
Upvotes: 1