Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
407 views
in Technique[技术] by (71.8m points)

.net - How to set and change the culture in WPF

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.)

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...