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.
Download
I’ve included a very simple project that you can download a play with.
After downloading the project, please change the extension from .doc to .zip. This is a requirement of WordPress.com.
Download Sample Project (76KB)
Steps To Reproduce Issue
Launch included program using debug mode.
Ensure Visual Studio Output window is visible.
Set each TextBox to 7.
Go to first TextBox. Clear field and press TAB. Notice nothing is added to the Output window.
Go to second TextBox. Clear field and press TAB. Notice nothing an exception is added to the Output window.
Close
When binding to Nullable types, use the TargetNullValue property along with the StringFormat property to avoid type mismatch exceptions.
Hope this tip has helped you learn more about WPF!
Have a great day!
Just a grain of sand on the worlds beaches.