programing

"실제" CultureInfo를 사용합니다.IetfLanguageTag의 CultureInfo가 아닌 WPF 바인딩의 현재 Culture

linuxpc 2023. 4. 26. 23:02
반응형

"실제" CultureInfo를 사용합니다.IetfLanguageTag의 CultureInfo가 아닌 WPF 바인딩의 현재 Culture

내 경우:

DateTime 유형의 속성에 대한 TextBlock Binding이 있습니다.사용자의 국가별 설정에 따라 표시되기를 원합니다.

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

WPF XAML 바인딩으로 언어 속성을 설정하고 있으며 Current Culture Display에 다음과 같이 표시됩니다.

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

그러나 이 코드 줄을 사용하면 CurrentCulture의 IetfLanguageTag가 말하는 CultureInfo의 기본 형식으로 텍스트를 표시할 뿐, 시스템 영역 설정에서 선택한 유효 값이 다음과 같이 표시되지 않습니다.

(예: "de-DE" DD의 경우).선택한 yyyy-MM-dd 대신 MM.yyyy가 사용됨)

지역 설정: 기본값은 아니지만 yyy-MM-dd가 사용됩니다.

바인딩이 모든 바인딩에 ConverterCulture를 정의하지 않고 올바른 형식을 사용하는 방법이 있습니까?

코드로

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

올바른 Culture 설정을 사용합니다.

편집:

원하는 대로 작동하지 않는 또 다른 방법(이와 같이).언어 = ... 수행):

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

그리고.

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

작성 시 ConverterCulture를 현재 culture로 자동 설정하는 바인딩의 하위 클래스(예: CultureAwareBinding)를 만들 수 있습니다.

완벽한 해결책은 아니지만 아마도 유일한 해결책일 것입니다. 문화를 존중하기 위해 바인딩을 소급적으로 강제하는 것은 이러한 행동에 의존하는 WPF의 다른 코드를 깰 수 있기 때문입니다.

도움이 더 필요하시면 말씀해주세요!

이것은 KzenT의 답변의 연장입니다.그들은 바인딩 클래스의 하위 클래스를 만들고 ConverterCulture를 CurrentCulture로 설정해야 한다고 제안했습니다.답변이 매우 간단하지만, 일부 사람들은 구현하는 것을 매우 불편하게 생각할 수도 있다고 생각하여, 저는 XAML에서 사용하는 방법의 예와 함께 KzenT의 답변 코드 버전을 공유합니다.

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

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

XAML에서 이 기능을 사용하는 방법의 예

네임스페이스를 XAML 파일로 가져와야 합니다.

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

CultureAware 바인딩의 실제 사용

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

UI를 초기화하기 전에 다음 줄의 코드를 입력합니다.이것은 저에게 효과가 있었습니다.

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

(그리고 모든 명시적인 배양 매개변수 제거)

당신의 두 번째 시도는 아슬아슬했고, 저에게 효과적인 해결책으로 이끌었습니다.

Converter Culture 설정의 문제는 Converter가 있을 때만 사용된다는 것입니다.따라서 형식을 매개 변수로 사용하는 간단한 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}}" />

저는 그 코드를 제 요구에 맞는 적절한 결과로 사용합니다.그것이 당신을 채울 수 있기를 바랍니다 :-)! "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>

바인딩을 모두 업데이트하지 않는 해킹/해결 방법을 생각해냈습니다.이 코드를 기본 창의 생성자에 추가합니다.

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

리플렉션을 사용하고 있기 때문에 앞으로 작동할 것이라는 보장은 없지만, 현재는 (.NET 4.6).

IVValueConverter를 사용하여 DateTimeConverter를 생성할 수 있습니다.

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

뒤에 있는 코드에서 라나게를 바꾸는 것은 어떻습니까?

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

"이것"을 사용하는 것을 피하는 것이 문제입니다.언어 = XmlLanguage.언어 가져오기(스레드).현재 스레드입니다.현재 문화.이름);"는 사실 흔한 것이 아닙니다.나는 여기 프랑스에서 날짜 형식을 미국이나 일본 형식으로 바꿀 사용자를 모릅니다. 단지 적어도 어떤 사용자도 그러한 변경이 가능하다는 것을 알고 있지 않기 때문입니다(그리고 어떻게 하는지 모릅니다).물론 "language="는 완벽하지는 않지만, 수년간 WPF 및 Silverlight를 사용해 온 사용자들에게 이런 종류의 문제가 발생한 적은 없습니다.그래서 저는 여전히 "Langage=" 트릭을 사용합니다. 이 트릭은 간단하고 실제 요구사항을 100% 충족합니다.물론 다른 솔루션이 더 나은 것 같지만, 그럴 필요는 없습니다. (그리고 "language=" 솔루션과 비교했을 때 완벽하지 않은 구현 몇 가지를 보았습니다.)

언급URL : https://stackoverflow.com/questions/5831455/use-real-cultureinfo-currentculture-in-wpf-binding-not-cultureinfo-from-ietfl

반응형