Используйте «настоящую» CultureInfo.CurrentCulture в привязке WPF, а не CultureInfo из IetfLanguageTag - PullRequest
36 голосов
/ 29 апреля 2011

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

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

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

Я устанавливаю свойство языка как Привязки WPF XAML и отображение CurrentCulture :

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

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

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

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

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

В коде

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

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

edit:

другой способ, который не работает должным образом (как это. Язык = ... делает):

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

и

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

Ответы [ 9 ]

26 голосов
/ 09 мая 2011

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

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

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

17 голосов
/ 05 ноября 2013

Это расширение ответа от 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}}" />
5 голосов
/ 25 июля 2016

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

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

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

2 голосов
/ 26 ноября 2015

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

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 голосов
/ 21 апреля 2015

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

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

Проблема с настройкой 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}}" />
0 голосов
/ 10 января 2019

Мы можем создать 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 голосов
/ 23 августа 2014

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

0 голосов
/ 19 июля 2012

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

this.Language = XmlLanguage.GetLanguage(Thread.CurrentThread.CurrentCulture.Name);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...