Formatting a string binding in XAML using a value converter
Introduction
WPF provides thorough support for formatting strings when binding using StringFormat or ContentStringFormat. However there are still scenarios where you will need to do some extra coding to get the results you want.
For example an application may have an alphanumeric order reference "ON1029HH00CD". A requirement might be for the reference to be displayed in a TextBlock or Label in a more friendly format: "ON:1029-HH00 CD"
This article shows how to achieve this using a value converter to format a string binding against a mask supplied as the value converter parameter. It’s relatively painless and reusable.
A code sample to accompany this article is available here.
Creating the value converter
Creating the value converter is quite straight forward. Create a new class (in this case called CustomStringFormatConverter) and implement the IValueConverter interface.
In order to change the format of the string we need to implement the Convert method. This has two parameters which we will use. The first is value represents the actual value being set in the binding. The second is parameter, which we will be setting to be a text mask to apply to the value.
As both value and parameter are expected to be strings the first step is to cast them both to string. If either is not a string, and the result of the cast is null the conversion is skipped and the Convert method returns DependencyProperty.UnsetValue. This will ensure that WPF uses the FallbackValue instead.
If everything is as expected with the value and parameter the MaskedTextProvider is used to format the text using the mask. If this fails for any reason, such as an invalid mask the code will fall through to return DependencyProperty.UnsetValue.
public class CustomStringFormatConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var mask = parameter as string;
var inString = value as string;
if (mask != null & inString != null)
{
MaskedTextProvider mtp = new MaskedTextProvider(mask);
if (mtp.Set(inString))
{
return mtp.ToDisplayString();
}
}
return DependencyProperty.UnsetValue;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
Using the converter
To put the converter to use the first thing to do is to add a namespace declaration in the XAML. Below is the reference from the sample application, in this case the converter is under the namespace CustomStringFormatExample.
<Window x:Class="CustomStringFormatExample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:CustomStringFormatExample"
...>
The next step is to add the value converter as a resource so it is available to use. Below is an example of how to add it as a window resource but you could use a resource dictionary instead.
<Window.Resources>
<local:CustomStringFormatConverter x:Key="CustomStringFormat"/>
</Window.Resources>
It is now ready to use so when setting the binding to the string that needs formatting specify the Converter (by the key given when declaring it as a resource), and set the mask as the ConverterParameter. For more details on the masking language see MSDN here.
<TextBlock Text="{Binding TestString, Converter={StaticResource CustomStringFormat},ConverterParameter='AA:AAAA-AAAA AA',FallbackValue='format failed'}"/>