New WPF 3.5 SP1 feature: Data Formatting (with Binding.StringFormat)
Background
Formatting data can be a pretty cumbersome task in WPF. To illustrate with a very simple example, let’s say I want to display the dollar value of some item in a TextBlock:
<StackPanel>
<TextBlock Text="Choose a number:"></TextBlock>
<ComboBox Name="myComboBox" SelectedIndex="0">
<ComboBoxItem>
<sys:Double>168.361</sys:Double>
</ComboBoxItem>
<ComboBoxItem>
<sys:Double>456.9832</sys:Double>
</ComboBoxItem>
</ComboBox>
<TextBlock>
<TextBlock.Text>
<Binding ElementName="myComboBox" Path="SelectedItem.Content"/>
</TextBlock.Text>
</TextBlock>
</StackPanel>
To add in a $ symbol and/or any other formatting, I would need to write my own ValueConverter and do the formatting there.
<!--added to resource section-->
<local:MoneyConverter x:Key="moneyConverter" />
<!--inside StackPanel-->
<TextBlock>
<TextBlock.Text>
<Binding ElementName="myComboBox" Path="SelectedItem.Content" Converter =" StaticResource moneyConverter" />
</TextBlock.Text>
</TextBlock>
public class MoneyConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return string.Format("Item cost: {0:C}", value);
}
// ConvertBack left out
}
It would be nice if I could just include the formatting as a definition with my binding. It would be more readable and self-documenting, as well as decrease the number of ValueConverter classes that I would need to write (which may not be very reusable in the rest of your application). Well, as it turns out this feature has been added in WPF 3.5 SP1.
What is it?
Strings can now be formatted directly in bindings, multibindings and many controls by String.Format(IFormatProvider, String, Object[]). Note that string formatting is only applied in the direction from source to target. Anytime the source is updated, the converter/formatting will be reapplied.
Examples
Single binding standard:
<TextBlock>
<TextBlock.Text>
<Binding ElementName="myComboBox" Path="SelectedItem.Content" StringFormat="Item cost: {0:C}"/>
</TextBlock.Text>
</TextBlock>
<TextBlock Text="{Binding ElementName=myComboBox, Path=SelectedItem.Content, StringFormat=Item cost: {0:C}}"/>
Single binding convenience:
<TextBlock>
<TextBlock.Text>
<Binding ElementName="myComboBox" Path="SelectedItem.Content" StringFormat="C"/>
</TextBlock.Text>
</TextBlock>
<TextBlock Text="{Binding ElementName=myComboBox, Path=SelectedItem.Content, StringFormat=C}"/>
Single binding escaping markup:
<TextBlock>
<TextBlock.Text>
<Binding ElementName="myComboBox" Path="SelectedItem.Content" StringFormat="{}{0:C}"/>
</TextBlock.Text>
</TextBlock>
<TextBlock Text="{Binding ElementName=myComboBox, Path=SelectedItem.Content, StringFormat=\{0:C\}"/>
Formatting in DisplayMemberBinding:
<GridViewColumn Header="Price" DisplayMemberBinding="{Binding Path=Price, StringFormat=C}"/>
MultiBinding:
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="Item1 cost: {0}, Item2 cost: {1}">
<Binding ElementName="myComboBox" Path="SelectedItem.Content"/>
<Binding ElementName="myComboBox2" Path="SelectedItem.Content"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
MultiBinding with a converter (note that the converter is called before the string is formatted):
<TextBlock>
<TextBlock.Text>
<MultiBinding Converter="{StaticResource sumConverter}" StringFormat="Total Item cost: {0}">
<Binding ElementName="myComboBox" Path="SelectedItem.Content"/>
<Binding ElementName="myComboBox2" Path="SelectedItem.Content"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
Many controls have also added a new property to set format on its content. For example, ContentControl has added ContentStringFormat, HeaderedContentControl has added HeaderStringFormat, and ItemsControl has added ItemStringFormat. These are only a few examples.
<Label ContentStringFormat="dddd – d - MMMM">
<sys:DateTime>2004/3/4 13:6:55</sys:DateTime>
</Label>
<Button ContentStringFormat="{}{0:MM/dd/yyyy}">
<sys:DateTime>2004/3/4 13:6:55</sys:DateTime>
</Button>
<ListBox Name="lb1" SelectedIndex="1" ItemStringFormat="F1">
<sys:Double>3.14159</sys:Double>
<sys:Double>2.71828</sys:Double>
</ListBox>
There are a lot more examples that can be shown for controls. I may do an additional post on that as it can seem a little complicated at first when dealing with controls that have multiple ways of setting format. Anyway, I hope that you may find this new feature useful. It will definitely be handy for the DataGrid.
Comments
Anonymous
May 17, 2008
I know I am a little late on blogging about .NET 3.5 SP1, but here goes... This is a huge release...Anonymous
May 18, 2008
cool stuff... P.S welcome to the blogging worldAnonymous
May 22, 2008
So far for the new WPF 3.5 SP1 features, I've surveyed Item Container Recycling , Data Formatting , andAnonymous
May 23, 2008
My latest links about WPF (Apps, Controls, 3.5sp1 beta, HowTo, for LOB), Silverlight, XAML and URLs WPFAnonymous
October 14, 2008
Is it possible to move StringFormat into a Style?Anonymous
October 17, 2008
The comment has been removedAnonymous
September 04, 2009
Is it possible to bind the culture info in the StringFormat as well?Anonymous
September 08, 2009
Poltex, Unfortunately no as CultureInfo is not a dependency property.Anonymous
November 13, 2009
Thanks for the informative article. I am trying to replace my current use of ValueConverters for string formatting with this nifty feature. I am receiving the following build error: The property 'StringFormat' does not exist on the type 'Binding' in the XML namespace 'http://schemas.microsoft.com/winfx/2006/xaml/presentation'. I have the following in my xaml: <TextBlock Text="{Binding Path=Date, StringFormat=D}"/> I have 3.5 SP1 and Visual Studio 2008 SP1 installed (I also installed the VS2010 Beta 2 if it is relevant) I would appreciate help in resolving this. ThanksAnonymous
December 14, 2009
Sreenivas, Is your project targeting an older framework version?