it-roy-ru.com

Используйте "настоящую" 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 из 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}" />
36
Markus k

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

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

Дай мне знать, если тебе еще понадобится помощь!

26
aKzenT

Это продолжение ответа от 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}}" />
17
Parth Shah

Поместите следующую строку кода перед инициализацией любого пользовательского интерфейса. Это сработало для меня.

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

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

5
Alan Hauge

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

Проблема с настройкой 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();
    }
}

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

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

Я использую этот код с подходящими результатами для моих нужд. Надеюсь, это может заполнить ваш :-)! Возможно, вам лучше создать исключение, если вы не можете "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>
2
Eric Ouellet

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

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

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

2
Joost van den Boom

Мы можем создать 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)));
        }
0
ASHOK MANGHAT