在WPF Binding中使用“真正的”CultureInfo.CurrentCulture,而不是来自IetfLanguageTag的CultureInfo

时间:2011-04-29 11:33:01

标签: c# wpf binding currentculture

就我而言:

我有一个TextBlock绑定到DateTime类型的属性。 我希望它显示为用户的区域设置。

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

我将语言属性设置为WPF XAML Bindings and CurrentCulture Display 表示:

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

但是使用这行代码,它只会将文本显示为CultureInfo的默认格式 与CurrentCulture的IetfLanguageTag说,不是在系统区域设置中选择的有效值说:

(例如,使用“de-DE” dd.MM.yyyy 而不是选择 yyyy-MM-dd

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

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

9 个答案:

答案 0 :(得分:26)

您可以创建一个绑定子类(例如CultureAwareBinding),它在创建时自动将ConverterCulture设置为当前文化。

这不是一个完美的解决方案,但它可能是唯一的解决方案,因为追溯强制Binding以尊重文化可能会破坏WPF中依赖于此行为的其他代码。

如果您需要更多帮助,请与我联系!

答案 1 :(得分:17)

这是来自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}}" />

答案 2 :(得分:5)

在初始化任何UI之前,请输入以下代码。这对我有用。

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

(并删除所有显式文化参数)

答案 3 :(得分:2)

你的第二次尝试很接近,并引导我找到一个对我有用的解决方案。

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

答案 4 :(得分:2)

我根据自己的需要使用该代码。希望它可以填满你的:-)! 如果不能“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>

答案 5 :(得分:2)

我提出了一个黑客/解决方法,可以避免更新所有绑定。将此代码添加到主窗口的构造函数中。

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 :(得分:0)

我们可以使用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)));
        }

答案 7 :(得分:-1)

如何更改后面代码中的语言?

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

答案 8 :(得分:-1)

避免使用&#34; this.Language = XmlLanguage.GetLanguage(Thread.CurrentThread.CurrentCulture.Name);&#34;实际上并不常见。我不知道法国的任何用户会将日期格式更改为美国或日本,只是因为至少没有用户知道这样的改变是可能的(并且不知道如何做)... 所以当然&#34;语言=&#34;并不完美,但在WPF和Silverlight实践的许多年里,我从来没有看到任何用户的这类问题...... 所以我仍然使用&#34; Langage =&#34;技巧,它很简单,涵盖了100%的实际需求。 当然,其他解决方案似乎更好,但没有必要(我看到一些实现与#34;语言=&#34;解决方案相比还远非完美。)