Partager via


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 world

  • Anonymous
    May 22, 2008
    So far for the new WPF 3.5 SP1 features, I've surveyed Item Container Recycling , Data Formatting , and

  • Anonymous
    May 23, 2008
    My latest links about WPF (Apps, Controls, 3.5sp1 beta, HowTo, for LOB), Silverlight, XAML and URLs WPF

  • Anonymous
    October 14, 2008
    Is it possible to move StringFormat into a Style?

  • Anonymous
    October 17, 2008
    The comment has been removed

  • Anonymous
    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. Thanks

  • Anonymous
    December 14, 2009
    Sreenivas, Is your project targeting an older framework version?