WPF Bindings and CurrentCulture Formatting

I was surprised to find today that while putting together some localization samples that by default WPF bindings do not respect the current culture. For example check out this localized form that has been localized to German and is running with both Culture and UICulture in the de-DE locale:

  BindingsFormattingMess

If you look at the highlighted formatting text you’ll notice that the form is localized (ie.the UICulture is applied) and that the active culture which in this case displays the CultureInfo.CurrentCulture is also set to German. But as you can see the date and number format is clearly using the default en-US formatting.

Apparently this is by design in WPF, although I can’t think of a single reason why this behavior should be so. Every other UI environment correctly assumes that if you have your culture set to a specific locale you’ll want your formatting and conversions to apply using this culture. But no that would be, uh too easy and nothing in WPF is easy after all.

Well, maybe it is, since the solution is relatively simple. All WPF elements include a Language property that can be assigned and determines the Culture that is used for formatting. The property is applied down the container hierarchy so setting the language at the top level container like the on the Window in the above form is all that’s needed.

Here’s the one liner:

this.Language = XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag);

Easy enough but not something that search turned up real easily. Just another one of those issues I fretted over for a couple of hours experimenting that makes WPF such an incredible time sink.

Note that it’s important that the language assignment happens before InitializeComponent in the constructor because the language is applied at load time:

public LocalizationInfo()
{
    // MAKE SURE you set the language of the page explicitly or else
    // all number and date formatting occurs using the neutral culture 
    this.Language = XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag);

    InitializeComponent();
    
    this.Loaded += LocalizationInfo_Loaded;            
}

You can also set the language globally for your entire application in the App class:

protected override void OnStartup(StartupEventArgs e)
{
    base.OnStartup(e);

    // Set application startup culture based on config settings
    string culture = ConfigurationManager.AppSettings["Culture"];
    SetCulture(culture);

    Theme = ConfigurationManager.AppSettings["Theme"];
    SetTheme(Theme);

    FrameworkElement.LanguageProperty.OverrideMetadata(typeof(FrameworkElement),
    new FrameworkPropertyMetadata(XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)));            
}

This will switch the default language for the entire application. You’ll want to use this only in startup code as this setting can be applied only once per application. You can still override individual forms when necessary using the explicit language override shown above.

Hopefully this will help somebody out by making this issue more readily findable.

And no jokes about my funky German localization. Even though I speak German fluently localizing a computer form is definitely not something I feel qualified for :-}.

posted @ 2012-04-18 15:40  reagent  阅读(415)  评论(0编辑  收藏  举报