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:
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 :-}.
The Voices of Reason
# re: WPF Bindings and CurrentCulture Formatting
# re: WPF Bindings and CurrentCulture Formatting
I hit the problem of CultureInfo.Current(UI)Culture resetting back after my change again in our localization .NET Standard code used in WPF/UWP/...
The cultures are changed on main (UI) thread with our SetCulture method, but resetted back after a while by the framework.
After adding second call of SetCulture method with UI SynchronizationContext.Post just after the first direct one, cultures are kept and not resetting back occures again. Tested only in WPF.
# re: WPF Bindings and CurrentCulture Formatting
# re: WPF Bindings and CurrentCulture Formatting
Yes thanks Rick - First page I went to from Google has saved me considerable time. Forever grateful.
# re: WPF Bindings and CurrentCulture Formatting
Anyone have any great ideas? Tks.
# re: WPF Bindings and CurrentCulture Formatting
Thanks again!
# re: WPF Bindings and CurrentCulture Formatting
I found that, for example if the Resources.resx file contains English texts, there's no need to have a separate Resources.en.resx file. .NET will automatically fall back to the "main" Resources file if the relevant culture-specific file can't be found.
Additionally it seems that although CultureInfo.CurrentCulture is correctly set to the current system culture, Thread.CurrentThread.CurrentUICulture is not. It's this property that determines which resource DLL will be loaded. So to automatically load the correct resources for the current system culture (which is surely the most common scenario) the code should be:
var cultureName = CultureInfo.CurrentCulture.Name; FrameworkElement.LanguageProperty.OverrideMetadata( typeof(FrameworkElement), new FrameworkPropertyMetadata( XmlLanguage.GetLanguage(cultureName))); Thread.CurrentThread.CurrentUICulture = CultureInfo.CurrentCulture;
# re: WPF Bindings and CurrentCulture Formatting
The only point I would make is that numeric date formats should never be used in an international environment.
In global terms a numeric only date format like 01/06/2008 is completely ambiguous. It means 6th January 2008 in some parts of the World and the 1st of June in most other parts of the World. Either version of 01-Jun-2008 or Jun-01-2008 is vastly more informative, my preference is to use 01-Jun-2008 as a more acceptable global date format.
Of course the month abbreviations must also be translated for internation use.
# re: WPF Bindings and CurrentCulture Formatting
It's a different story in Web apps where you are absolutely right because you're not likely to be able to capture everybody's locale accurately.
Do like the date format you're proposing as a general rule and we're just giving up 1 extra character for the more readable version. This is a custom date format string right (dd-MMM-yyyy)?
# re: WPF Bindings and CurrentCulture Formatting
1. Who own the laptop and where was it set up?
2. European employee working in US forgets or does not know that US have a different date format.
3. US employee working in Europe forgets or does not know that UK have a different date format.
4. Variable programming standards, how can we be sure that the local culture is being used.
As you said, it is mostly a problem with world wide web applications, but there are destop applications out there that just cannot be trusted. How can an application user be certain?
Yes the format used is dd-MMM-yyyy.
# re: WPF Bindings and CurrentCulture Formatting
In some countries the official and proper way to display dates is established by law and is important that software follows the law, especially for software used in public service, which happens to be the largest consumers of programs.
The fact that WPF's controls don't follow the CurrentCulture is a biggie and is a defect that should be addressed, but as Mr. Strahl pointed out, it's by design, so it's not likely to change (and I would like to choke the guy who decided that, since I had to debug a large app suite that makes use of different programs written in different frameworks, and the WPF ones wouldn't follow what the control panel stated). It's especially annoying the fact that it's only WPF that does that. If all of the controls in the whole .NET framework would do that, it would be one thing, but it's not the case.
The points you brought up are user training issues, and shouldn't be addressed by jacking around with the framework.
On a totally unrelated issue, Mr. Strahl, when I look at the comment preview, I see at the bottom the "Remember Me" checkbox, and the following text:
1253 of <%= App.Configuration.CommentMaxLength %> characters
Thought you might wanna know..
# re: WPF Bindings and CurrentCulture Formatting
This has always been a sticky situation. I'd almost prefer that there was no default in C# to force developers to always think everytime they emit a DateTime, or if the defaults were to use an invariant culture so that any presentation errors are easily corrected, but config files and other text processing isn't affected, or was already dealt with and doesn't change 'by accident' when switching the regional settings.
Like the luddite, I vote to be rid of completely numeric dates altogether. dd-MMM-yyyy is understandable by most.
# re: WPF Bindings and CurrentCulture Formatting
I've been following your difficulties with WPF through your blog but cannot unfortunately help you on the internationalisation; however I would be intrigued to know how you feel the process of development in WPF compares to WinForms/AJAX WebForms - does it actually turn out to be longer to build an application ? For my part, I have consistently found my programming teams take 2-3 times longer to build a WebForms based application than a WinForms based one (even a multi-tier web forms one), just because of the aggravation and "friction" of developing browser based systems. Of course that doesn't mean one is somehow superior as a development paradigm or toolset, but I would have expected a new technique such as WPF (and by extension Silverlight) to close the programmer-efficiency gap. Have you any opinion on whether its made it easier/faster ?
Phil H
# re: WPF Bindings and CurrentCulture Formatting
WPF is problematic for me in a number of ways: a) The time it takes to lay out UI takes much much longer than WinForms. I suppose if I wanted to compare apples to apples I could use Canvas for everything and do positional layout which would speed things up but negate some of the advantages of WPF. And b) WPF is very, very complex and there are many inconsistencies and quirks like this one mentioned in this post that make you go WTF were they thinking? These by far are the biggest time sinks sometimes taking hours to resolve or even understand. Additionally it seems like the WPF teams are not good at listening to customer feedback as the pain points that people are running into have not been addressed in 3 years and 2 updates since WPF has been out.
WPF is interesting because there's so much that you CAN do with it and so much control you have over the environment, but it's so complex that it takes a long time to understand all the details. Everytime I start with it I find something where I go, man this is so cool and this makes my life so much easier, only to be slapped down by some other feature that's lacking a crucial piece as to be worthless. It's a mixed bag, but the learning curve for me at least has been intense and honestly I can't say that it was worth it... (and I'm not even close to done with my learning curve).
# WPF Productivity
I personally always wondered what problem WPF was trying to solve. There are libraries for WinForms (my current one being the Telerik user interface library) which make a decent job of making apps look pretty and are good performance. They might even be using DX under the hood for all I know. I realise the idea of a single portable screen definition language, seperating the logic from the layout, and usable in Silverlight and Windows, is a valid idea; but I think they should have chosen one route to get there, not the two Silverlight + WPF differing routes. Even now I believe WPF not to be completely compatible with Silverlight and porting of interface definitions is still a lowest-common-denominator exercise (though I'm happy to be corrected on that point).
Thanks again for your insights.
# re: WPF Bindings and CurrentCulture Formatting
# re: WPF Bindings and CurrentCulture Formatting
On a related side note, here's a great little tool makes it really easy to test a compiled app under different culture settings.
http://khason.net/blog/how-to-test-localized-application/
# re: WPF Bindings and CurrentCulture Formatting
# re: WPF Bindings and CurrentCulture Formatting
But I think it's also a different story re: developer tools vs. mainstream applications. Blend is all WPF for example. Yet Expression Web (which has a similar *looking* API) is not. It seems to me that MS is very selective of what they try WPF out on <s>...
# re: WPF Bindings and CurrentCulture Formatting
... ... ... /// <summary> /// Event that fires on application startup /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void OnStartup(object sender, StartupEventArgs e) { //Uri uri = new Uri("pack://application:,,,/Views/MainWindow.xaml", UriKind.RelativeOrAbsolute); //Application.Current.StartupUri = uri; try { // Ensure the current culture passed into bindings // is the OS culture. By default, WPF uses en-US // as the culture, regardless of the system settings. try { // per http://msdn.microsoft.com/en-us/library/system.globalization.cultureinfo.ietflanguagetag(v=vs.110).aspx var cultureName = CultureInfo.CurrentCulture.Name; FrameworkElement.LanguageProperty.OverrideMetadata( typeof(FrameworkElement), new FrameworkPropertyMetadata( XmlLanguage.GetLanguage(cultureName))); } catch (Exception ex) { ex.PreserveExceptionDetail(); throw; } ... ... ...
Also the following use of
IetfLanguageTag
this.Language = XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag);
which is why the source snippet above uses:
var cultureName = CultureInfo.CurrentCulture.Name;
Basically I was getting exceptions on startup because the framework elements (the visual tree?) were not yet instantiated. Dumb, I know, but frustrating. So this is now firing AFTER the app gets going, when the OnStartup event fires, and behaves nicely there.
Here is the main App constructor:
App()
{
// 3) Force just one copy to run
try
{
// Setup unhandled exception handlers
#region Handlers For Unhandled Exceptions
// anything else to do on startup can go here and will fire after the base startup event of the application
// First make sure anything after this is handled
// Creates an instance of the class holding delegate methods that will handle unhandled exceptions.
CustomExceptionHandler eh = new CustomExceptionHandler();
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(eh.OnAppDomainException);
// this ensures that any unhandled exceptions bubble up to a messagebox at least
Dispatcher.CurrentDispatcher.UnhandledException += new DispatcherUnhandledExceptionEventHandler(eh.OnDispatcherUnhandledException);
#endregion Handlers For Unhandled Exceptions
this.ForceSingleInstance();
this.Startup += this.OnStartup;
this.Exit += this.OnExit;
this.LoadCompleted += this.OnLoadCompleted;
CableStay.Instance.Wire(App.AppDisplayName, false);
this.ShutdownMode = ShutdownMode.OnExplicitShutdown;
InitializeComponent();
}
catch (Exception ex)
{
ex.PreserveExceptionDetail();
throw;
}
}
You can see that OnStartup is added to the handlers, some other stuff goes on, then InitializeComponent is called. Alternatively this thing can be called after InitializeComponent but ONLY if InitializeComponent() does not work with any FrameworkElement objects, which is highly unlikely.
# re: WPF Bindings and CurrentCulture Formatting
What does it do? Have you implemented them yourself or are they implemented in .NET?