Formatting Your WPF Data – String.Format is in the House!
Join the DZone community and get the full member experience.
Join For FreeHi.
When working with WPF I always found myself thinking how to handle Data formatting when a WPF control was bound to it. Let’s look at the following example of a window with a TextBlock that displays a DateTime:
<Window x:Class="BindingFormat.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>
<TextBlock Text="{Binding}"></TextBlock>
</Grid>
</Window>
And the code behind:
public Window1()
{
InitializeComponent();
DateTime d = DateTime.Now;
this.DataContext = d;
}
Very Simple.
The outcome is this:
But what if we wanted to change the format of the DateTime? Before .NET 3.5 SP1 we had 2 options:
Adding a Property
That was the easiest and fastest way to make the data in the UI formatted in the way you wanted let’s say we wanted the DateTime to display like this: 11:49 2/5/2009, we would have done this:
public Window1()
{
InitializeComponent();
this.DataContext = this;
}
public string Now
{
get
{
return DateTime.Now.ToString("HH:MM d/M/yyyy");
}
}
and have the UI bind to the Now property:
<Window x:Class="BindingFormat.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>
<TextBlock Text="{Binding Now}"></TextBlock>
</Grid>
</Window>
The outcome is what we wanted:
I don’t like this way of work for 2 reasons:
- It ads clutter to the code behind and mixes data and UI elements because the Now property is strictly UI but it resides in the Data of the application.
- There is no way to reuse it, we would have to duplicate the property anywhere we need to display this particular format.
Using a ValueConverter
This is a much better way of work because it solves the 2 problems I had with the Property method of formatting data. Using a converter keeps UI logic in the UI, removes the clutter from the code behind and is reusable.
Here is how we do it:
First we add the converter:
public class DateTimeConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is DateTime)
{
DateTime d = (DateTime)value;
return d.ToString("HH:MM d/M/yyyy");
}
return string.Empty;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
Use it with the binding:
<Window x:Class="BindingFormat.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:BindingFormat"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<local:DateTimeConverter x:Key="BindingCVR"/>
</Window.Resources>
<Grid>
<TextBlock Text="{Binding Converter={StaticResource BindingCVR}}"/>
</Grid>
</Window>
And have the DataContext be DateTime.Now:
public Window1()
{
InitializeComponent();
DateTime d = DateTime.Now;
this.DataContext = d;
}
And the outcome? Just as before:
The only drawback to this method is that it is takes more effort.
But we just got lucky..
Using Binding.StringFormat
In .NET 3.5 SP1 we got the StringFormat option in Binding!
This makes things so much easier All we have to do is have the Binding Expression look like this:
<TextBlock Text="{Binding StringFormat='HH:MM d/M/yyyy'}"/>
And that’s it, no extra Properties and ValueConverters.
I could have copied the image again but trust me it gives the same outcome in a much more elegant way.
Do you have a different way of work? let me know.
Enjoy
Amit
Published at DZone with permission of Amit Raz. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments