簡體   English   中英

在 WPF 綁定中使用“真正的” CultureInfo.CurrentCulture,而不是來自 IetfLanguageTag 的 CultureInfo

[英]Use “real” CultureInfo.CurrentCulture in WPF Binding, not CultureInfo from IetfLanguageTag

就我而言:

我有一個文本塊綁定到日期時間類型的屬性。 我希望它按照用戶的區域設置顯示。

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

我將 Language 屬性設置為WPF XAML Bindings 和 CurrentCulture Display說:

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

但是使用這行代碼,它只是將文本顯示為 CultureInfo 的默認格式,CurrentCulture 的 IetfLanguageTag 說,而不是系統區域設置中選擇的有效值說:

(例如,對於“de-DE”,使用dd.MM.yyyy代替選定的yyyy-MM-dd

區域設置:不是默認但使用yyy-MM-dd

有沒有辦法 Binding 使用正確的格式而不在每個 Binding 上定義 ConverterCulture?

在代碼中

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}" />

您可以創建綁定的子類(例如 CultureAwareBinding),它在創建時將 ConverterCulture 自動設置為當前區域性。

這不是一個完美的解決方案,但它可能是唯一的解決方案,因為追溯強制綁定尊重文化可能會破壞 WPF 中取決於此行為的其他代碼。

如果您需要更多幫助,請告訴我!

這是 aKzenT 答案的擴展。 他們建議我們應該創建一個 Binding class 的子類,並將 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}}" />

在初始化任何 UI 之前放置以下代碼行。 這對我有用。

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

(並刪除所有顯式文化參數)

我使用該代碼並根據我的需要獲得適當的結果。 希望它可以滿足您的需求:-)。 如果不能“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>

我想出了一個避免更新所有綁定的技巧/解決方法。 將此代碼添加到主 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)。

您的第二次嘗試很接近,並讓我找到了一個對我有用的解決方案。

設置 ConverterCulture 的問題在於它僅在您擁有 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}}" />

我們可以使用 IValueConverter 創建一個 DateTime 轉換器

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

避免使用“this.Language = XmlLanguage.GetLanguage(Thread.CurrentThread.CurrentCulture.Name);”的問題不是一個真正的常見的。 我不知道法國有任何用戶會將日期格式更改為美國或日本格式,因為至少沒有用戶知道這樣的更改是可能的(並且不知道該怎么做)......所以當然“語言=”並不完美,但是在WPF和Silverlight的多年實踐中,我從未見過任何用戶出現這種問題......所以我仍然使用“語言=”技巧,它簡單而覆蓋100%的真實需求。 當然其他解決方案似乎更好,但沒有必要(我看到一些與“語言=”解決方案相比遠非完美的實現)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM