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.