Thursday, June 11, 2009

Formatted TimeSpan WPF Binding

The .Net TimeSpan object is displayed in a fixed format when bound to a WPF control. If you need to display a TimeSpan with a custom format you need to do this via a converter class that derives from IValueConverter.

class TimeSpanConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, System.Globalization.CultureInfo culture)
{
TimeSpan timeSpan = (TimeSpan) value;
String result = String.Empty;
if ( timeSpan != null )
{
result = String.Format(
"{0:D2}:{1:D2}:{2:D2}:{3:D2}.{4:D1}",
timeSpan.Days, timeSpan.Hours,
timeSpan.Minutes, timeSpan.Seconds,
(int) Math.Round( timeSpan.Milliseconds/100.0));
}
return result;
}

public object ConvertBack(object value, Type targetType,
object parameter, System.Globalization.CultureInfo culture)
{
return null;
}
}

You can create an instance of the Converter class in the Windows resources as follows:
Window.Resources
srm:TimeSpanConverter x:Key="TimeSpanConverter" /srm:TimeSpanConverter
Window.Resources

and use this converter in the binding with the following XAML

GridViewColumn Header="Duration" DisplayMemberBinding=
"{Binding Path=Duration, Converter={StaticResource TimeSpanConverter}}"


Update

I now use the following which has support for an option ConvertParameter:

        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
String result = String.Empty;
if ( value is TimeSpan )
{
TimeSpan timeSpan = (TimeSpan) value;
if (timeSpan != TimeSpan.Zero)
{
if (parameter == null || !(parameter is string))
result = String.Format("{0:D2}:{1:D2}:{2:D2}:{3:D2}.{4:D1}",
timeSpan.Days, timeSpan.Hours, timeSpan.Minutes, timeSpan.Seconds, (int)Math.Round(timeSpan.Milliseconds / 100.0));
else
{
DateTime time = DateTime.Today;
time = time.Add(timeSpan);
result = time.ToString((string)parameter);
}
}
}
return result;
}
XAML:
Binding="{Binding Path=Duration, ConverterParameter=H:mm:ss.f, Converter={StaticResource TimeSpanConverter}}"

1 comment:

  1. If the value is null the cast will fail, so checking if timeSpan is not null is meaning less, I think you meant using as operator

    ReplyDelete