Проблеми з локалізацією StringFormat у wpf


112

У WPF 3.5SP1 я використовую останню функцію StringFormat у DataBindings:

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

Проблема, з якою я стикаюся, полягає в тому, що дата завжди форматується англійською мовою ... хоча моя система є французькою? Як я можу змусити дату слідувати даті системи?


14
3 роки високо оцінене питання, але відповіді не зазначено! Сумні обличчя навколо.
Гусдор

Відповіді:


212
// 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
Дякую, що ви вирішили мій головний біль.
Скурмедель

9
Чудово. Але що робити, якщо культура змінюється протягом життєвого циклу програми (наприклад, користувач може змінити бажану культуру в діалоговому вікні налаштувань). Відповідно до документації FrameworkElement.LanguageProperty.OverrideMetadata не можна викликати більше одного разу (це кидає виняток)
TJKjaer

1
@pengibot Це рішення працює для мене. Я використовую .net 4 / C # / WPF і вводжу код у метод OnStartup.
Бьорн

18
Зауважте, що елемент Run не успадковує FrameworkElement , тому, якщо ви прив'язуєте дати тощо до запуску, вам знадобиться додатковий виклик для 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

Я просто хотів додати, що відповідь лорадерона в більшості випадків працює чудово. Коли я поміщаю наступний рядок коду у своєму App.xaml.cs, дати моїх TextBlocks відформатуються у правильній культурі.

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's в 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 - «правильна» культура. Він повинен скоріше взяти налаштування з машини користувача.
misnomer

Дуже дякую, саме це я шукав! Якщо 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"

Якщо ви робите це за допомогою коду замість XAML, це наступне:binding.ConverterCulture = System.Globalization.CultureInfo.CurrentCulture;
Metalogic

8

Якщо вам потрібно змінити мову під час роботи програми, ви можете просто змінити властивість мови на вашому кореневому елементі (я не впевнений, чи це миттєвий ефект, або якщо підлемент потрібно відтворити, в моєму випадку це працює принаймні)

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();
    }
}

0

Якщо ви працюєте над кодом, а не XAML, ви можете встановити ConverterCulture наступним чином:

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

Kudos to @KZeise, щоб вказати на тонку різницю між використанням визначення культури за замовчуванням та використанням індивідуального визначення культури користувача.


-3

Використовуйте мітку (включаючи культуру), а не текстовий блок

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.