One of the great features introduced in .NET 3.5 Framework Service Pack 1 is the BindingBase StringFormat
property. When used in a data binding expression the StringFormat
property replaces most IValuteConverters that were used for formatting
of values in WPF 3.0 & WPF 3.5 applications.
Here are two examples of the StringFormat property in action formatting a currency field:
<TextBox Text="{Binding Path=Salary, StringFormat=c}" /> <TextBox Text="{Binding Path=Salary, StringFormat=\{0:c\}}" />
Nullable Type in the Mix
If you are binding to a non-Nullable data type the above will work just fine.
However, if you are binding to a Nullable data type the above will not work.
This breaks down when a UI Control like a TextBox as a value and the
user clears the TextBox and press TAB. The default implementation of
StringFormat will attempt to set the Target Property to an empty string
which in the the case of a Nullable Decimal property will cause the
following or similar data binding exception. The below data binding
exception can be viewed in the Visual Studio Output window.
Exception
System.Windows.Data
Error: 7 : ConvertBack cannot convert value ” (type ‘String’).
BindingExpression:Path=Age; DataItem=’Customer’ (HashCode=31884011);
target element is ‘TextBox’ (Name=”); target property is ‘Text’ (type
‘String’) FormatException:’System.FormatException: Input string was not
in a correct format.
at
System.Number.StringToNumber(String str, NumberStyles options,
NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
at System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info)
at System.String.System.IConvertible.ToInt32(IFormatProvider provider)
at System.Convert.ChangeType(Object value, Type conversionType, IFormatProvider provider)
at MS.Internal.Data.SystemConvertConverter.ConvertBack(Object o, Type type, Object parameter, CultureInfo culture)
at
System.Windows.Data.BindingExpression.ConvertBackHelper(IValueConverter
converter, Object value, Type sourceType, Object parameter, CultureInfo
culture)’
TargetNullVaue to the Rescue
In the above example, the exception is thrown because of a type
mismatch. In WPF 3.0 and 3.5 I had a set of Nullable ValueConverters
for my applications to handle this problem.
Another great feature introduced in .NET 3.5 Framework Service Pack 1 is the BindingBase TargetNullValue
property. This property can be used to handled the type mismatch
problem when converting an empty string from a TextBox to Nothing (null)
when the binding pipeline sets the target Nullable property.
Let’s have a look at the two below TextBoxes.
<TextBox Grid.Column="1" Grid.Row="1" Margin="0,11,11,11" VerticalAlignment="Top" Text="{Binding Path=NumberOfComputers, TargetNullValue={x:Static sys:String.Empty}, StringFormat=\{0:D\}}" /> <TextBox Grid.Column="1" Grid.Row="2" Margin="0,11,11,11" VerticalAlignment="Top" Text="{Binding Path=Age, StringFormat=\{0:D\}}" />
These TextBoxes are both bound to Nullable properties. The first
TextBox takes advantage of the TargetNullValue property and works as
expected. The second does not. The data binding pipeline will throw
an exception when the second TextBox is changed to an empty string and
it attempts to assign the value of String.Empty to the Target property.
Here is a potential problem. If the exception gets thrown and
swallowed because the code didn’t check for this, the user thinks they
cleared a value but the property the TextBox is bound to never gets
changed due to the exception being thrown.