I have a .NET 4.0 WPF application where the user can change the language (culture) I simply let the user select a language, create a corresponding CultureInfo and set:
Thread.CurrentThread.CurrentCulture = cultureInfo;
Thread.CurrentThread.CurrentUICulture = cultureInfo;
In the C# code this works fine. However in the WPF controls the culture is still en-US. This means for example that dates will be shown in the US format instead of whatever is correct for the current culture.
Apparently, this is not a bug. According to MSDN and several blog posts and articles on StackOverflow the WPF language does not automatically follow the current culture. It is en-US until you do this:
FrameworkElement.LanguageProperty.OverrideMetadata(
typeof(FrameworkElement),
new FrameworkPropertyMetadata(
XmlLanguage.GetLanguage(CultureInfo.CurrentUICulture.IetfLanguageTag)));
See for example StringFormat Localization issues in wpf.
I do not completely understand what is going on here. It seems the Language property on all frameworkelements is set to the current culture. Anyway, it works. I do this when the application starts up and now all controls works as expected, and e.g. dates is formatted according to the current culture.
But now the problem: According to MSDN FrameworkElement.LanguageProperty.OverrideMetadata
can only be called once. And indeed, if I call it again (when the user changes the language) it will throw an exception. So I haven't really solved my problem.
The question: How can I reliably update the culture in WPF more than once and at any time in my applications life cycle?
(I found this when researching: http://www.nbdtech.com/Blog/archive/2009/03/18/getting-a-wpf-application-to-pick-up-the-correct-regional.aspx and it seems he has something working there. However, I can't imagine how to do this in my application. It seems I would have to update the language in all open windows and controls and refresh all existing bindings etc.)
I'm going to chime in here.
I successfully did this using the OverrideMetadata()
method that the OP mentioned:
var lang = System.Windows.Markup.XmlLanguage.GetLanguage(MyCultureInfo.IetfLanguageTag);
FrameworkElement.LanguageProperty.OverrideMetadata(
typeof(FrameworkElement),
new FrameworkPropertyMetadata(lang)
);
But, I still found instances in my WPF in which the system culture was being applied for dates and number values. It turned out these were values in <Run>
elements. It was happening because the System.Windows.Documents.Run
class does not inherit from System.Windows.FrameworkElement
, and so the overriding of metadata on FrameworkElement
obviously had no effect.
System.Windows.Documents.Run
inherits its Language
property from System.Windows.FrameworkContentElement
instead.
And so the obvious solution was to override the metadata on FrameworkContentElement
in the same way. Alas, doing do threw an exception (PropertyMetadata is already registered for type System.Windows.FrameworkContentElement), and so I had to do it on the next descendant ancestor of Run
instead, System.Windows.Documents.TextElement
:
FrameworkContentElement.LanguageProperty.OverrideMetadata(
typeof(System.Windows.Documents.TextElement),
new FrameworkPropertyMetadata(lang)
);
And that sorted out all my issues.
There are a few more sub-classes of FrameworkContentElement
(listed here) which for completeness should have their metadata overridden as well.