Как установить и изменить культуру в WPF

У меня есть приложение .NET 4.0 WPF, в котором пользователь может изменить язык (культуру). Я просто разрешаю пользователю выбирать язык, создавать соответствующий CultureInfo и устанавливать:

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

В коде C # это отлично работает. Однако в WPF контролирует культуру по-прежнему в США. Это означает, например, что даты будут отображаться в формате США, а не то, что подходит для текущей культуры.

По-видимому, это не ошибка. Согласно MSDN и нескольким сообщениям в блоге и статьям о StackOverflow, язык WPF автоматически не отслеживает текущую культуру. Это en-US, пока вы это сделаете:

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

См. Например, Проблемы локализации StringFormat в wpf .

Я не совсем понимаю, что здесь происходит. Кажется, что свойство Language на всех элементах структуры задано текущей культурой. Во всяком случае, он работает. Я делаю это, когда приложение запускается, и теперь все элементы управления работают так, как ожидалось, и, например, даты форматируются в соответствии с текущей культурой.

Но теперь проблема: согласно MSDN FrameworkElement.LanguageProperty.OverrideMetadata можно вызывать только один раз. И действительно, если я снова его назову (когда пользователь меняет язык), это вызовет исключение. Поэтому я не решил свою проблему.

Вопрос: Как я могу достоверно обновлять культуру в WPF более одного раза и в любое время в жизненном цикле приложений?

(Я нашел это при исследовании: http://www.nbdtech.com/Blog/archive/2009/03/18/getting-a-wpf-application-to-pick-up-the-correct-regional.aspx, и он похоже, у него что-то работает. Однако я не могу представить, как это сделать в моем приложении. Кажется, мне нужно будет обновить язык во всех открытых windowsх и элементах управления и обновить все существующие привязки и т. д.),

Я собираюсь перезвонить здесь.

Я успешно сделал это, используя метод OverrideMetadata() который упоминал OP:

 var lang = System.Windows.Markup.XmlLanguage.GetLanguage(MyCultureInfo.IetfLanguageTag); FrameworkElement.LanguageProperty.OverrideMetadata( typeof(FrameworkElement), new FrameworkPropertyMetadata(lang) ); 

Но я все еще нашел экземпляры в своем WPF, в котором система была применена к датам и значениям числа. Оказалось, что это значения в элементах . Это происходило, потому что class System.Windows.Documents.Run не наследуется от System.Windows.FrameworkElement , и поэтому переопределение метаданных в FrameworkElement явно не повлияло.

System.Windows.Documents.Run вместо этого наследует свойство Language из System.Windows.FrameworkContentElement .

Таким образом, очевидным решением было переопределение метаданных в FrameworkContentElement таким же образом. Увы, делает исключение ( PropertyMetadata уже зарегистрирован для типа System.Windows.FrameworkContentElement ), и поэтому я должен был сделать это у следующего потомка-потомка Run вместо System.Windows.Documents.TextElement :

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

И это разобрало все мои проблемы.

Существует еще несколько подclassов FrameworkContentElement (перечисленных здесь ), которые для полноты должны также переопределять метаданные.

Я не уверен, как обойти исключение «не могу назвать OverrideMetadata несколько раз».

В качестве обходного пути, когда пользователь изменяет культуры пользовательского интерфейса в вашем приложении, вы можете перезапустить приложение с этой культурой, передав новую культуру в качестве аргумента командной строки. Если ваши пользователи часто меняют культуры, это звучит как разумное решение.

Я никогда не нашел способ сделать именно то, что я просил в вопросе. В моем случае я решил это решить, получив все мои пользовательские элементы, наследуемые от суперclassа, который содержал это:

 ///  /// Contains shared logic for all XAML-based Views in the application. /// Views that extend this type will have localization built-in. ///  public abstract class ViewUserControl : UserControl { ///  /// Initializes a new instance of the ViewUserControl class. ///  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's constructor is executed before the type's // own constructor (which call InitializeComponent()) this is as it // should be for classes extending this this.Language = XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag); } } 

Когда пользователь меняет язык, я создаю новые экземпляры любых пользовательских элементов управления, которые в настоящее время запущены.

Это решило мою проблему. Тем не менее, мне все равно хотелось бы сделать это «автоматически» (т.е. без необходимости отслеживать какие-либо объекты-объекты).

Только мои два цента: после того, как я с ума сошел, когда пытаюсь внедрить элементы управления WPF ComponentOne (DataGrid и C1DatePicker) с моей сборкой на немецком языке, я наткнулся на эту страницу.

Кажется, это правильное направление: я только что ввел вышеуказанный код в мою процедуру App.xaml.cs / Application_startup, и теперь немецкое форматирование даты и времени для C1DatePicker, наконец, работает.

После этого нужно проверить DataGrid.

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

Благодаря!

Обновление: проверено C1DataGrid для WPF – работает! Это решило все проблемы, которые у меня были с международными настройками Дата / Время в моих Приложениях. Большой!

У меня в значительной степени была такая же проблема.

Я нашел это: http://www.codeproject.com/Articles/35159/WPF-Localization-Using-RESX-Files (возможно, не оригинальный источник).

В нем обсуждается расширение разметки с именем «UICultureExtension», которое привязано к языковому признаку всех элементов структуры, которым требуется локализация (в XAML).

Если вы измените событие изменения языка пользовательского интерфейса, статические менеджеры по расширению в фоновом режиме обновят все зарегистрированные элементы структуры.

Адаптивное OverrideMetadata

Некоторая форма перезагрузки неизбежна, потому что изменение свойства Language управления не делает его обновлением его текста.

Тем не менее, есть способ переопределить метаданные, которые позволяют вам установить его один раз и новые элементы управления автоматически используют текущую культуру:

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

где 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); } 

Само по себе этого недостаточно, потому что только что созданные элементы управления получат значение по умолчанию System.Windows.Markup.XmlLanguage.Empty без его принудительного принуждения. Однако, если вы затем установите xml:lang="" в вашем XAML windows, это будет принудительно, а затем каждый новый элемент управления увидит, что он наследует значение от своего родителя и будет принуждать его. В результате новые элементы управления, добавленные в это окно, будут использовать текущий язык.

PS Как и во многих вещах в WPF, было бы намного проще, если бы они не стремились держать вещи в internal . DefaultValueFactory был бы гораздо более изящным способом сделать это.

перезарядка

Самый экстремальный, но, следовательно, надежный способ перезагрузки – просто создать новое главное окно и отказаться от старого.

Практически столь же экстремально, но не совсем, так это упорядочить настройку языка только в очень простой области основного windows с очень маленькой загрузкой, и это очень мало, чтобы полностью привязать базу данных к модели, которая поддерживает принудительное изменение свойства для уведомления все.

Существующие ответы на этот вопрос имеют другие предложения.

Это не совсем ваш ответ, но я использовал это для перезагрузки ресурсов. Но вам все равно нужно перезагрузить windows …

  List dictionaryList = new List(); 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); } 
  • Проблемы с локализацией строки StringFormat в wpf
  • как установить языковой стандарт по умолчанию для моей JVM?
  • Что обычно лучше всего использовать - StringComparison.OrdinalIgnoreCase или StringComparison.InvariantCultureIgnoreCase?
  • Каков список поддерживаемых языков / локалей на Android?
  • Игнорирование акцентированных букв в сравнении строк
  • Локализация приложений для iPhone - проблемы с английским языком?
  • Как изменить язык приложения, когда пользователь выбирает язык?
  • Как определить, принадлежит ли персонаж языку Right To Left?
  • Как преобразовать String в Double в Java, используя определенную локаль?
  • Исключительные сообщения на английском языке?
  • Как изменить культуру приложения WinForms во время выполнения
  • Давайте будем гением компьютера.