How to set and change culture in WPF

I have a .NET 4.0 WPF application where the user can change the language (culture) I just let the user select the language, create the appropriate CultureInfo and install:

Thread.CurrentThread.CurrentCulture = cultureInfo; Thread.CurrentThread.CurrentUICulture = cultureInfo; 

In C # code, this works great. However, WPF still controls the culture in the United States. This means, for example, that dates will be displayed in US format instead of what is correct for the current culture.

This is apparently not a mistake. According to MSDN and a few blog posts and StackOverflow articles, WPF does not automatically track the current culture. This is en-US until you do this:

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

See for example Problems localizing a StringFormat string in wpf .

I do not quite understand what is happening here. It seems that the Language property on all structural elements is set by the current culture. Anyway, it works. I do this when the application starts, and now all the controls work as expected, and for example, the dates are formatted according to the current culture.

But now the problem: on MSDN FrameworkElement.LanguageProperty.OverrideMetadata can be called only once. Indeed, if I call it again (when the user changes the language), this will throw an exception. Therefore, I did not solve my problem.

Question: how can I reliably update the culture in WPF more than once and at any time in the application 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, something seems to work for him there. However, I cannot imagine how to do it in my application. It seems that I will need to update the language in all open windows and controls and update all existing bindings, etc.)

+48
wpf localization
Oct 28 '10 at 8:48
source share
7 answers

I never found a way to do exactly what I asked in the question. In my case, I decided to solve this by getting all my user elements inherited from the superclass that contained this:

 /// <summary> /// Contains shared logic for all XAML-based Views in the application. /// Views that extend this type will have localization built-in. /// </summary> public abstract class ViewUserControl : UserControl { /// <summary> /// Initializes a new instance of the ViewUserControl class. /// </summary> protected ViewUserControl() { // This is very important! We make sure that all views that inherit // from this type will have localization built-in. // Notice that the following line must run before InitializeComponent() on // the view. Since the supertype constructor is executed before the type // own constructor (which call InitializeComponent()) this is as it // should be for classes extending this this.Language = XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag); } } 

When the user changes the language, I create new instances of any user controllers that are currently running.

This solved my problem. However, I would still like to do this "automatically" (that is, without having to track any object objects).

+5
Nov 16 '10 at 13:30
source share
โ€” -

I'm going to call back 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 was applied for dates and number values. It turned out that these are the values โ€‹โ€‹in the <Run> elements. This happened because the System.Windows.Documents.Run class does not inherit from System.Windows.FrameworkElement , so overriding metadata on FrameworkElement clearly has no effect.

System.Windows.Documents.Run instead inherits its Language property from System.Windows.FrameworkContentElement .

So, the obvious solution was to override the metadata on the FrameworkContentElement in the same way. Alas, throw an exception (PropertyMetadata is already registered for the type System.Windows.FrameworkContentElement), and so I had to do this on the following ancestor of the Run instead of System.Windows.Documents.TextElement :

 FrameworkContentElement.LanguageProperty.OverrideMetadata( typeof(System.Windows.Documents.TextElement), new FrameworkPropertyMetadata(lang) ); 

And that sorted out all my problems.

There are several subclasses of FrameworkContentElement (listed here ) that must also have overridden metadata for completeness.

+8
Feb 06 '14 at 12:59 on
source share

I am not sure how to get around the exception โ€œI cannot call OverrideMetadata several timesโ€.

As a workaround, when a user changes the user interface culture in your application, you can restart the application with that culture by passing the new culture as a command line argument. If your users often change cultures, it sounds like a smart solution.

+5
Nov 08 '10 at 19:55
source share

Only my two cents: after the craziness when trying to implement WPF ComponentOne controls (DataGrid and C1DatePicker) with my German assembly, I came across this page.

This seems to be the right direction: I just entered the above code into my App.xaml.cs / Application_startup procedure, and now the German date and time formatting for C1DatePicker finally works.

Now you need to check the DataGrid.

  private void Application_Startup(object sender, StartupEventArgs e) { FrameworkElement.LanguageProperty.OverrideMetadata( typeof(FrameworkElement), new FrameworkPropertyMetadata( System.Windows.Markup.XmlLanguage.GetLanguage(CultureInfo.CurrentUICulture.IetfLanguageTag))); } 

Thank!

Update: Tested C1DataGrid for WPF - Works! This solved all the problems that I had with the international Date / Time settings in my Applications. Fine!

+4
Feb 11 '13 at 17:19
source share

I pretty much had the same problem.

I found this: http://www.codeproject.com/Articles/35159/WPF-Localization-Using-RESX-Files (maybe not the original source).

It discusses a markup extension called "UICultureExtension", which is tied to the "Language" property of all structural elements that require localization (in XAML).

If you change an event with a changed user interface, static extension managers in the background will update all registered elements of the framework.

+3
Jul 24 '13 at 8:42 on
source share

Responsive Override Metadata h2>

Some form of reloading is inevitable because changing the Language control does not make it an update to its text.

However, there is a way to override metadata that allows you to set once and new controls automatically use the current culture:

 FrameworkElement.LanguageProperty.OverrideMetadata( typeof(FrameworkElement), new FrameworkPropertyMetadata( System.Windows.Markup.XmlLanguage.Empty, default(PropertyChangedCallback), _CoerceCurrentXmlLang)); 

where is CoerceValueCallback -

 private static object _CoerceCurrentXmlLang(DependencyObject d, object baseValue) { var lang = baseValue as System.Windows.Markup.XmlLanguage; var culture = System.Globalization.CultureInfo.CurrentUICulture; return lang != null && lang.IetfLanguageTag.Equals(culture.Name, StringComparison.InvariantCultureIgnoreCase) ? lang : System.Windows.Markup.XmlLanguage.GetLanguage(culture.Name); } 

This alone is not enough, because the newly created controls will get the default value of System.Windows.Markup.XmlLanguage.Empty without coercion. However, if you then set xml:lang="" to the XAML window, this will be forced, and then each new control will see that it inherits the value from its parent and force it. As a result, new controls added to this window will use the current language.

PS As with many things in WPF, it would be much simpler if they did not try to keep things internal . DefaultValueFactory would be a much more elegant way to do this.

reloading

The most extreme, but, therefore, reliable way to reboot is to simply create a new main window and abandon the old one.

Almost as extreme, but not quite so that the language setting was changed only in a very simple panel of the main window with a very small load, and that very little was completely tied to the presentation model, which supports forcing the changed notification property for everything.

The existing answers to this question have other suggestions.

+3
Jan 28 '16 at 15:51
source share

This is not entirely your answer, but I used this to reload resources. But you still need to reload windows ...

  List<Uri> dictionaryList = new List<Uri>(); foreach (ResourceDictionary dictionary in Application.Current.Resources.MergedDictionaries) { dictionaryList.Add(dictionary.Source); } Application.Current.Resources.MergedDictionaries.Clear(); foreach (Uri uri in dictionaryList) { ResourceDictionary resourceDictionary1 = new ResourceDictionary(); resourceDictionary1.Source = uri; Application.Current.Resources.MergedDictionaries.Add(resourceDictionary1); } 
+1
Nov 09 '10 at 8:18
source share



All Articles