StringFormat Проблемы с локализацией в wpf

112

В WPF 3.5SP1 я использую последнюю функцию StringFormat в DataBindings:

     <TextBlock Text="{Binding Path=Model.SelectedNoteBook.OriginalDate, StringFormat='f'}"
                FontSize="20" TextTrimming="CharacterEllipsis" />

Проблема, с которой я сталкиваюсь, заключается в том, что дата всегда форматируется на английском языке ... хотя моя система на французском языке? Как я могу заставить дату следовать системной дате?

Павел Аниховский
источник
14
3 года на вопрос с высоким рейтингом, но без ответа! Вокруг грустные лица.
Gusdor

Ответы:

213
// 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.
FrameworkElement.LanguageProperty.OverrideMetadata(
      typeof(FrameworkElement),
      new FrameworkPropertyMetadata(
          XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)));

Из создания интернационализированного мастера в WPF

лорадерон
источник
17
Да, это довольно неприятно. +1
Szymon Rozga
2
Спасибо, что разрешили мою головную боль.
Skurmedel
9
Отлично. Но что делать, если культура меняется в течение жизненного цикла приложения (например, пользователь может изменить предпочитаемую культуру в диалоговом окне настроек). Согласно документации, FrameworkElement.LanguageProperty.OverrideMetadata не может быть вызван более одного раза (выдает исключение)
TJKjaer
1
@pengibot Это решение работает для меня. Я использую .net 4 / C # / WPF и помещаю код в метод OnStartup.
Björn
18
Обратите внимание, что элемент Run не наследуется от FrameworkElement , поэтому, если вы привязываете даты и т. Д. К Run, вам понадобится дополнительный вызов для typeof (System.Windows.Documents.Run)
Мэт Фергюссон,
90

Определите следующее пространство имен xml:

xmlns:gl="clr-namespace:System.Globalization;assembly=mscorlib"

А теперь взгляните на это фантастическое исправление:

<TextBlock Text="{Binding Path=Model.SelectedNoteBook.OriginalDate, StringFormat='f', ConverterCulture={x:Static gl:CultureInfo.CurrentCulture}" FontSize="20"TextTrimming="CharacterEllipsis" />

Я хорошо понимаю, что это не глобальное исправление, и оно потребуется вам в каждой из ваших привязок, но, конечно же, это просто хороший XAML? Насколько мне известно, в следующий раз, когда привязка обновится, она будет использовать правильную CultureInfo.CurrentCultureили все, что вы предоставили.

Это решение немедленно обновит ваши привязки с правильными значениями, но кажется, что много кода для чего-то настолько редкого и безобидного.

Гусдор
источник
4
Превосходно! Это сработало чудесно! У меня нет проблем с добавлением этого в те немногие места, где это необходимо.
Между прочим, в
3
Превосходная работа. Это так странно, что WPF по умолчанию использует американский английский, в отличие от текущего языка.
Крис Адамс,
12

Я просто хотел добавить, что ответ loraderon отлично работает в большинстве случаев. Когда я помещаю следующую строку кода в свой App.xaml.cs, даты в моих текстовых блоках форматируются с использованием правильного языка и региональных параметров.

FrameworkElement.LanguageProperty.OverrideMetadata(typeof(FrameworkElement), new FrameworkPropertyMetadata(System.Windows.Markup.XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)));

Я говорю "в большинстве случаев". Например, это будет работать из коробки:

<TextBlock Text="{Binding Path=Date, StringFormat={}{0:d MMMM yyyy}}" />
--> "16 mei 2013" (this is in Dutch)

... но при использовании Run в TextBlock DateTime форматируется в культуре по умолчанию.

<TextBlock>
  <Run Text="Datum: " />
  <Run Text="{Binding Path=Date, StringFormat={}{0:d MMMM yyyy}, Mode=OneWay}" />
</TextBlock>
--> "Datum: 16 may 2013" (this is in English, notice the
    name of the month "may" vs. "mei")

Чтобы это сработало, мне нужен был ответ Гусдора , а именно добавление ConverterCulture = {x: Static gl: CultureInfo.CurrentCulture} в привязку.

<TextBlock>
  <Run Text="Datum: " />
  <Run Text="{Binding Path=Date, StringFormat={}{0:d MMMM yyyy}, ConverterCulture={x:Static gl:CultureInfo.CurrentCulture}, Mode=OneWay}" />
</TextBlock>
--> "Datum: 16 mei 2013" (=Dutch)

Надеюсь, этот дополнительный ответ будет кому-то полезен.

Даниэль Тюнкенс
источник
Действительно, Run не является производным от FrameworkElement. Вы можете попробовать изменить ответ Лорадерона, чтобы повторить его код для базы Run (FrameworkContentElement), а также для FrameworkElement.
Натан Филлипс,
Для тех, кто может задаться вопросом: xmlns: gl = "clr-namespace: System.Globalization; assembly = mscorlib"
Игорь
11

Просто вставьте ярлык культуры в тег верхнего уровня:

xml:lang="de-DE"

например:

<Window x:Class="MyApp"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xml:lang="de-DE"
    Title="MyApp" Height="309" Width="497" Loaded="Window_Loaded">....</Window>
Геррит Хорейс
источник
5
Но это так же плохо, как предполагать, что en-US является «правильной» культурой. Он должен скорее брать настройки с машины пользователя.
неправильное название
Спасибо большое, это именно то, что я искал! Если WPF считает, что en-EN является правильной культурой для любой ситуации, я тоже могу использовать свою локализацию. Поскольку я работаю над экспериментальным приложением, в котором скорость разработки является нормой дня, у меня нет времени возиться с десятками строк кода только для того, чтобы заставить одну DatePickerвыполнять свою работу, поэтому это простое исправление получилось меня быстро вернули в нужное русло!
M463
лучший ответ для моего случая, наконец-то искал целую вечность :) и, конечно, это правильно, либо вы предполагаете, что это en-US, либо de-DE ... у людей всегда есть проблемы с простыми решениями -.-
MushyPeas
10

Как уже говорилось, по умолчанию XAML использует инвариантный язык и региональные параметры (en-US), и вы можете использовать

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

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

Чтобы действительно использовать текущую культуру с настройками, вам нужно будет установить ConverterCultureвместе с StringFormat, как в

Text="{Binding Day, StringFormat='d', ConverterCulture={x:Static gl:CultureInfo.CurrentCulture}}"

с glопределенным как глобальное пространство имен в вашем корневом элементе

xmlns:gl="clr-namespace:System.Globalization;assembly=mscorlib"
KZeise
источник
Если вы делаете это с помощью кода вместо XAML, это выглядит следующим образом:binding.ConverterCulture = System.Globalization.CultureInfo.CurrentCulture;
Metalogic
8

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

element.Language = System.Windows.Markup.XmlLanguage.GetLanguage(culture.IetfLanguageTag);
Питер
источник
он немедленно переоценивается, но, к сожалению, должен быть установлен для каждого корневого элемента (окна) отдельно
Firo
6

Полный код для переключения локализации также в таких элементах, как <Run />это:

Private Shared Sub SetXamlBindingLanguage()

    '' For correct regional settings in WPF (e.g. system decimal / dot or comma) 
    Dim lang = System.Windows.Markup.XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)
    FrameworkContentElement.LanguageProperty.OverrideMetadata(GetType(TextElement), New FrameworkPropertyMetadata(lang))
    FrameworkContentElement.LanguageProperty.OverrideMetadata(GetType(DefinitionBase), New FrameworkPropertyMetadata(lang))
    FrameworkContentElement.LanguageProperty.OverrideMetadata(GetType(FixedDocument), New FrameworkPropertyMetadata(lang))
    FrameworkContentElement.LanguageProperty.OverrideMetadata(GetType(FixedDocumentSequence), New FrameworkPropertyMetadata(lang))
    FrameworkContentElement.LanguageProperty.OverrideMetadata(GetType(FlowDocument), New FrameworkPropertyMetadata(lang))
    FrameworkContentElement.LanguageProperty.OverrideMetadata(GetType(TableColumn), New FrameworkPropertyMetadata(lang))
    FrameworkElement.LanguageProperty.OverrideMetadata(GetType(FrameworkElement), New FrameworkPropertyMetadata(lang))

End Sub
Хабакук
источник
0

Если вы хотите изменить информацию о культуре во время выполнения, вы можете использовать поведение (см. Ниже)

  public class CultureBehavior<TControl> : Behavior<TControl>
    where TControl : FrameworkElement
{
    private readonly IEventAggregator _eventAggregator;
    private readonly Action<CultureInfo> _handler;

    public CultureBehavior()
    {
        _handler = (ci) => this.AssociatedObject.Language = XmlLanguage.GetLanguage(ci.IetfLanguageTag);
        _eventAggregator = IoC.Container.Resolve<IEventAggregator>();
    }

    protected override void OnAttached()
    {
        base.OnAttached();

        _eventAggregator
            .GetEvent<LanguageChangedEvent>()
            .Subscribe(_handler);

        _handler.Invoke(CultureInfo.CurrentCulture);
    }

    protected override void OnDetaching()
    {
        _eventAggregator
            .GetEvent<LanguageChangedEvent>()
            .Unsubscribe(_handler);

        base.OnDetaching();
    }
}
user3173620
источник
0

Если вы работаете с кодом, а не с XAML, вы можете установить ConverterCulture следующим образом:

binding.ConverterCulture = System.Globalization.CultureInfo.CurrentCulture;

Престижность @KZeise за указание на тонкую разницу между использованием определения культуры по умолчанию и использованием пользовательского определения культуры.

металогики
источник
-3

Используйте Label (включая Cultture), а не texblock

Дэвид
источник