I wanted to format a TimeSpan in XAML and differentiate it from a normal time format, something like this 02h30m
After a bit of fiddling with curly brackets and back slashes I settled on:
"{Binding Path=Duration, StringFormat={}{0:hh}h{0:mm}m}"
One step forward, two steps back
"{Binding Path=Duration, StringFormat={}{0:hh}h{0:mm}m}"
public partial class MainWindow : Window
{
public String FormattedDate
{
get { return String.Format("{0:dd MMM yyy}", DateTime.Now); }
}
public String DateToString
{
get { return DateTime.Now.ToString("dd MMM yyy"); }
}
public DateTime RawDateTime
{
get { return DateTime.Now; }
}
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
}The first two TextBlocks bind directly to the pre-formatted properties. <TextBlock Text="{Binding FormattedDate}" />
<TextBlock Text="{Binding DateToString}" />Or we can bind to the raw data and use StringFormat. We can escape the curly braces in a couple of ways. <TextBlock Text="{Binding Path=RawDateTime, StringFormat=\{0:dd MMM yyyy\}}" />
<TextBlock Text="{Binding Path=RawDateTime, StringFormat={}{0:dd MMM yyyy}}" />The leading curly braces in the second version can be replaced by constant text that is rendered as part of the formatted string. But it seems a bit "sensitive" so I don't use it. <TextBlock Text="{Binding Path=RawDateTime, StringFormat=Today is {0:dd MMM yyyy}}" />
Next up is a Converter for which we need an IValueConverter class:class DateConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is DateTime)
{
return ((DateTime)value).ToString("dd MMM yyy");
}
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}And the corresponding XAML to use the Converter: xmlns:local="clr-namespace:WpfWaltz"
...
<Window.Resources>
<local:DateConverter x:Key="dateConverter"; />
</Window.Resources>
...
<TextBlock Text="{Binding Path=RawDateTime, Converter={StaticResource dateConverter}}" />
Finally, I had assumed that the indexer in the StringFormat was just a necessary evil since it was always 0: and hadn't considered using StringFormat with a MultiBinding like this: <TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0:dd MMM yyyy} {1:hh:mm:ss}">
<Binding Path="RawDateTime" />
<Binding Path="RawDateTime" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
The StringFormatting project that has all the code can be downloaded from GoogleCode.
<DataGridTextColumn Header="Blah" Binding="{Binding Blah}">
<DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="TextAlignment" Value="Right" />
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>Alternatively the style can be set up as StaticResource if it needs to be referenced by several DataGrid columns.
<Style x:Key="rightAlignedColumn" TargetType="{x:Type TextBlock}">
<Setter Property="TextAlignment" Value="Right" />
</Style>
...
<DataGridTextColumn Header="Blah"
Binding="{Binding Blah}"
ElementStyle="{StaticResource rightAlignedColumn}">
</DataGridTextColumn>
<DataGridTextColumn.CellStyle>
<Style>
<Setter Property="FrameworkElement.HorizontalAlignment" Value="Right" />
</Style>
</DataGridTextColumn.CellStyle>
public class DoNothingConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value;
}
}
protected void SetValue(T newValue, Action validate)
{
...
validate.Invoke(newValue);
...
} That worked fine until I wanted to change the value (for formatting purposes). So I moved to using the Func
protected T SetValue(T newValue, Func validate)
{
...
newValue = validate.Invoke(newValue);
...
}
| Sample | Generates |
| String.Format(”->{1,10}<-”, “Hello”); | -> Hello<- |
| String.Format(”->{1,-10}<-”, “Hello”); | ->Hello <- |
| Specifier | Type | Format | Output (Passed Double 1.42) | Output (Passed Int -12400) |
| c | Currency | {0:c} | $1.42 | -$12,400 |
| d | Decimal (Whole number) | {0:d} | System.FormatException | -12400 |
| e | Scientific | {0:e} | 1.420000e+000 | -1.240000e+004 |
| f | Fixed point | {0:f} | 1.42 | -12400.00 |
| g | General | {0:g} | 1.42 | -12400 |
| n | Number with commas for thousands | {0:n} | 1.42 | -12,400 |
| r | Round trippable | {0:r} | 1.42 | System.FormatException |
| x | Hexadecimal | {0:x4} | System.FormatException | cf90 |
| Specifier | Type | Example | Output (Passed Double 1500.42) | Note |
| 0 | Zero placeholder | {0:00.0000} | 1500.4200 | Pads with zeroes. |
| # | Digit placeholder | {0:(#).##} | (1500).42 | |
| . | Decimal point | {0:0.0} | 1500.4 | |
| , | Thousand separator | {0:0,0} | 1,500 | Must be between two zeroes. |
| ,. | Number scaling | {0:0,.} | 2 | Comma adjacent to Period scales by 1000. |
| % | Percent | {0:0%} | 150042% | Multiplies by 100, adds % sign. |
| e | Exponent placeholder | {0:00e+0} | 15e+2 | Many exponent formats available. |
| Specifier | Type | Example (Passed System.DateTime.Now) |
| d | Short date | 10/12/2002 |
| D | Long date | December 10, 2002 |
| t | Short time | 10:11 PM |
| T | Long time | 10:11:29 PM |
| f | Full date & time | December 10, 2002 10:11 PM |
| F | Full date & time (long) | December 10, 2002 10:11:29 PM |
| g | Default date & time | 10/12/2002 10:11 PM |
| G | Default date & time (long) | 10/12/2002 10:11:29 PM |
| M | Month day pattern | December 10 |
| r | RFC1123 date string | Tue, 10 Dec 2002 22:11:29 GMT |
| s | Sortable date string | 2002-12-10T22:11:29 |
| u | Universal sortable, local time | 2002-12-10 22:13:50Z |
| U | Universal sortable, GMT | December 11, 2002 3:13:50 AM |
| Y | Year month pattern | December, 2002 |
| Specifier | Type | Example | Example Output |
| dd | Day | {0:dd} | 10 |
| ddd | Day name | {0:ddd} | Tue |
| dddd | Full day name | {0:dddd} | Tuesday |
| f, ff, … | Second fractions | {0:fff} | 932 |
| gg, … | Era | {0:gg} | A.D. |
| hh | 2 digit hour | {0:hh} | 10 |
| HH | 2 digit hour, 24hr format | {0:HH} | 22 |
| mm | Minute 00-59 | {0:mm} | 38 |
| MM | Month 01-12 | {0:MM} | 12 |
| MMM | Month abbreviation | {0:MMM} | Dec |
| MMMM | Full month name | {0:MMMM} | December |
| ss | Seconds 00-59 | {0:ss} | 46 |
| tt | AM or PM | {0:tt} | PM |
| yy | Year, 2 digits | {0:yy} | 02 |
| yyyy | Year | {0:yyyy} | 2002 |
| zz | Timezone offset, 2 digits | {0:zz} | -05 |
| zzz | Full timezone offset | {0:zzz} | -05:00 |
| : | Separator | {0:hh:mm:ss} | 10:43:20 |
| / | Separator | {0:dd/MM/yyyy} | 10/12/2002 |
| Specifier | Type |
| g | Default (Flag names if available, otherwise decimal) |
| f | Flags always |
| d | Integer always |
| x | Eight digit hex. |