WPF Tips n' Tricks – Have all your dates, times, numbers... in the local culture
This is the first instance of a series where I'll try to publish at least
one trick a day you'll find useful in your .net 3 development life. Some of it I came up with myself, some of it comes from the forums. I'll make sure to give credit where credit is due :)
WPF has a very annoying tendency. All dates are by default in the en-US format. You need to understand first why, and then I'll give a few potential solutions, and one that is now my favorite.
You'll notice that UIElement has a property called Language. This property is supposed to define what language the element has been written in. That way, WPF can know when some content is en-US (American English), or en-GB (British English), etc. It is also bound to the xml:lang property you can set on any xml document.
Now if you read the documentation the way I did, you realize that xml:lang by *default* is set to the empty string, and as such doesn't have any associated culture. But by default, the matching Language property has a default of... en-US! And because of the way bindings work, that's why all your dates will always show up in American English format.
Whenever you bind an element's property to a DateTime object, the binding is going to covert the DateTime to the type of the property you're binding to. Take for example the following binding:
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
<Grid>
<TextBlock Text="{Binding Path={x:Static sys:DateTime.Now}}" />
</Grid>
</Window>
This will convert from DateTime to a String (the type of the Text property). But to do so, it is going to use a default converter. If you check the documentation for bindings, you'll see that you can specify an IValueConverter in the Converter property. And you'll also see a ConverterCulture property that specify which culture you want to use to convert your data, here our DateTime object.
As I said before, without a Converter specified, WPF will find one automatically for you, either built-in ones or using the existing conversion infrastructure that has been around for now three versions. But guess what happens when you don't specify a ConverterCulture?
WPF selects the culture of the Language property of the element on which the binding is applied. In our case, the default: en-US again!
So here's my trick of the day. To ensure your application defaults to the current culture *on the client machine* and *at run time*, you can add one simple line in your App.xaml.cs.
public partial class App : Application
{
static App()
{
FrameworkElement.LanguageProperty.OverrideMetadata(
typeof(FrameworkElement),
new FrameworkPropertyMetadata(
XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)));
}
}
What this bit of code does is override the default value of the Language property on all the FrameworkElement inherited classes in your application to the CurrentCulture of the computer you run on. In this case, we're interested in overriding this value so that any content is assumed by default to be in the language associated with the way you want your localization to be made. This is quite wrong, as explained by Michael in his Why we have both CurrentCulture and CurrentUICulture post, but it's the solution approaching the most an acceptable outcome.
As for what Microsoft probably should have done? Set by default the Binding.ConverterCulture property to the CultureInfo.CurrentCulture value. But that's just my opinion :)