Подтвердить что ты не робот

Используйте "real" CultureInfo.CurrentCulture в привязке WPF, а не CultureInfo от IetfLanguageTag

В моем случае:

У меня есть привязка TextBlock к свойству типа DateTime. Я хочу, чтобы он отображался в соответствии с региональными настройками пользователя.

<TextBlock Text="{Binding Date, StringFormat={}{0:d}}" />

Я устанавливаю свойство языка как WPF XAML Bindings и CurrentCulture Display говорит:

this.Language = XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag);

Но с этой строкой кода он просто отображает текст как формат по умолчанию CultureInfo с IetfLanguageTag of CurrentCulture говорит, а не как эффективное значение, выбранное в настройках области системы, говорит:

(например, для "de-DE" dd.MM.yyyy используется вместо выбранного yyyy-MM-dd)

Region settings: not the default but yyy-MM-dd is used

Есть ли способ Binding использует правильный формат без определения ConverterCulture на каждом отдельном Binding?

В коде

string.Format("{0:d}",Date);

использует правильные настройки культуры.

изменить

другой способ, который не работает по желанию (например this.Language =...):

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

и

<Binding Source="{x:Static glob:CultureInfo.CurrentCulture}" 
 Path="IetfLanguageTag" 
 ConverterCulture="{x:Static glob:CultureInfo.InvariantCulture}" />
4b9b3361

Ответ 1

Вы можете создать подкласс привязки (например, CultureAwareBinding), который автоматически устанавливает преобразовательCulture в текущую культуру при создании.

Это не идеальное решение, но оно, вероятно, единственное, поскольку ретроактивное принуждение Binding для уважения к культуре может разорвать другой код в WPF, который зависит от этого поведения.

Сообщите мне, если вам нужна дополнительная помощь!

Ответ 2

Это расширение ответа от aKzenT. Они предложили создать подкласс класса Binding и установить ConverterCulture в CurrentCulture. Несмотря на то, что ответ очень прост, я чувствую, что некоторые люди могут не очень удобно его реализовать, поэтому я использую версию кода ответа AKzenT на примере использования XAML.

using System;
using System.Globalization;
using System.Windows.Data;

namespace MyWpfLibrary
{
    public class CultureAwareBinding : Binding
    {
        public CultureAwareBinding()
        {
            ConverterCulture = CultureInfo.CurrentCulture;
        }
    }
}

Пример использования этого метода в XAML

1) Вам нужно импортировать пространство имен в файл XAML:

<Page
    ...
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:myWpfLib="clr-namespace:MyWpfLibrary;assembly=<assembly_name>"
    ...
>

2) Использование в реальном мире технологии CultureAwareBinding

<Textblock Text="{myWpfLib:CultureAwareBinding Path=Salary, Source=Contact, StringFormat={}{0:C}}" />

Ответ 3

Поместите следующую строку кода, прежде чем инициализируется какой-либо интерфейс. Это сработало для меня.

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

(И удалите все явные параметры культуры)

Ответ 4

Ваша вторая попытка была близка и привела меня к решению, которое действительно работает для меня.

Проблема с настройкой ConverterCulture заключается в том, что она используется только при наличии конвертера. Поэтому просто создайте простой StringFormatConverter, который принимает формат в качестве параметра:

public sealed class StringFormatConverter : IValueConverter
{
    private static readonly StringFormatConverter instance = new StringFormatConverter();
    public static StringFormatConverter Instance
    {
        get
        {
            return instance;
        }
    }

    private StringFormatConverter()
    {
    }

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return string.Format(culture, (string)parameter, value);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotSupportedException();
    }
}

Затем вы можете настроить привязку (при условии, что вы импортировали пространство имен преобразователя как "мое" )

<TextBlock Text="{Binding Date, Converter={x:Static my:StringFormatConverter.Instance}, ConverterCulture={x:Static glob:CultureInfo.CurrentCulture}, ConverterParameter={}{0:d}}" />

Ответ 5

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

XmlLanguage language = XmlLanguage.GetLanguage("My-Language");
typeof(XmlLanguage).GetField("_compatibleCulture", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(language, CultureInfo.CurrentCulture);
this.Language = language;

Поскольку он использует отражение, нет гарантии, что он будет работать в будущем, но на данный момент он выполняет (.NET 4.6).

Ответ 6

Я использую этот код с надлежащими результатами для моих нужд. Надеюсь, это может заполнить ваши:-)! Возможно, вы лучше выбрасываете исключение, если не можете "TryParse". До вас.

public sealed class CurrentCultureDoubleConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return ((double)value).ToString((string)parameter ?? "0.######", CultureInfo.CurrentCulture);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        double result;
        if (Double.TryParse(value as string, NumberStyles.Number, CultureInfo.CurrentCulture, out result))
        {
            return result;
        }

        throw new FormatException("Unable to convert value:" + value);
        // return value;
    }
}

Использование:

<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:simulatorUi="clr-namespace:SimulatorUi"
        xmlns:Converter="clr-namespace:HQ.Wpf.Util.Converter;assembly=WpfUtil" x:Class="SimulatorUi.DlgTest"
        Title="DlgTest" Height="300" Width="300">
    <Window.DataContext>
        <simulatorUi:DlgTestModel/>
    </Window.DataContext>

    <Window.Resources>
        <Converter:CurrentCultureDoubleConverter x:Key="CurrentCultureDoubleConverter"/>
    </Window.Resources>

    <Grid>
        <TextBox Text="{Binding DoubleVal, Converter={StaticResource CurrentCultureDoubleConverter}}"/>
    </Grid>
</Window>

Ответ 7

Мы можем создать DateTime Converter, используя IValueConverter

[ValueConversion(typeof(DateTime), typeof(String))]
    class DateTimeToLocalConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (!(value is DateTime)) return "Invalid DateTime";
            DateTime DateTime = (DateTime)value;
            return DateTime.ToLocalTime().ToShortDateString();

        }


        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }


    }

Примените это в XAML, как показано ниже

Binding="{Binding Path=createdDateTime,Converter={StaticResource DateTimeConverter}}"

Также измените текущую культуру, чтобы получить желаемый формат, который необходимо применить при запуске приложения.

/// <summary>
        /// Set Culture
        /// </summary>
        private void SetCulture() {
            var newCulture = new CultureInfo("en-IN");
            newCulture.DateTimeFormat.ShortDatePattern = "dd-MMM-yyyy";
            newCulture.DateTimeFormat.LongDatePattern = "dd-MMM-yyyy";
            newCulture.DateTimeFormat.FullDateTimePattern = "dd-MMM-yyyy";
            CultureInfo.DefaultThreadCurrentCulture = newCulture;
            CultureInfo.DefaultThreadCurrentUICulture = newCulture;
            Thread.CurrentThread.CurrentCulture = newCulture;
            Thread.CurrentThread.CurrentUICulture = newCulture;
            FrameworkElement.LanguageProperty.OverrideMetadata(typeof(FrameworkElement), new FrameworkPropertyMetadata(
                System.Windows.Markup.XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)));
        }

Ответ 8

Как насчет изменения lanaguge в коде?

this.Language = XmlLanguage.GetLanguage(Thread.CurrentThread.CurrentCulture.Name);

Ответ 9

Проблема, которая позволяет избежать использования this.Language = XmlLanguage.GetLanguage(Thread.CurrentThread.CurrentCulture.Name); на самом деле не является общим. Я не знаю ни одного пользователя здесь, во Франции, который изменит формат даты на американский или японский, только потому, что, по крайней мере, ни один пользователь не знает, что такое изменение возможно (и не знаю, как это сделать)... Поэтому, конечно, "язык =" не идеален, но за многие годы работы WPF и Silverlight я никогда не вижу проблемы такого рода с любым пользователем... Поэтому я все еще использую трюк "Langage =", он прост и покрывает 100% реальных потребностей. Конечно, другие решения кажутся лучше, но нет необходимости (и я видел несколько реализаций, которые далеки от совершенства по сравнению с решением "language =" ).