在 WPF 绑定中使用“真实”CultureInfo.CurrentCulture,而不是 IetfLanguageTag 中的 CultureInfo
Posted
技术标签:
【中文标题】在 WPF 绑定中使用“真实”CultureInfo.CurrentCulture,而不是 IetfLanguageTag 中的 CultureInfo【英文标题】:Use "real" CultureInfo.CurrentCulture in WPF Binding, not CultureInfo from IetfLanguageTag 【发布时间】:2011-08-15 10:40:28 【问题描述】:就我而言:
我有一个文本块绑定到日期时间类型的属性。 我希望它显示为用户所说的区域设置。
<TextBlock Text="Binding Date, StringFormat=0:d" />
我将 Language 属性设置为 WPF XAML Bindings and CurrentCulture Display 说:
this.Language = XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag);
但是使用这行代码它只是将文本显示为 CultureInfo 的默认格式 用 CurrentCulture 的 IetfLanguageTag 说的,而不是系统区域设置中选择的有效值说的:
(例如,对于“de-DE”,使用 dd.MM.yyyy 代替选定的 yyyy-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" />
【问题讨论】:
查看以下内容:***.com/questions/2764615/… @Pavlo:这个问题的答案也是使用 IetfLanguageTag 来获取 CultureInfo。 【参考方案1】:您可以创建绑定的子类(例如 CultureAwareBinding),在创建时将 ConverterCulture 自动设置为当前文化。
这不是一个完美的解决方案,但它可能是唯一的解决方案,因为追溯强制绑定尊重文化可能会破坏 WPF 中取决于此行为的其他代码。
如果您需要更多帮助,请告诉我!
【讨论】:
感谢您的回答。这个解决方案听起来是唯一可能的。 “因为追溯强制绑定尊重文化可能会破坏 WPF 中取决于此行为的其他代码。” - 我认为从长远来看,继续保持这样的破碎行为比引入短期休息更糟糕。或者他们可以修复它,但使用 .NET 的程序集绑定功能来检测应用程序何时需要旧版本并为它们维护损坏的行为。太疯狂了,这个错误已经在 WPF 中存在 12 年了,而且他们没有自己的CultureAwareBinding
内置。【参考方案2】:
这是来自 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" />
【讨论】:
我喜欢你对此的详细解释。关于纠正某些绑定错误的任何输入?这会导致类似“类型“CultureAwareBinding”不包含具有指定数量参数的构造函数。” 我还没有看到那个错误。我需要查看一些代码来确定为什么会发生这种情况。也许您可以在 Stack Overflow 上发布一个新问题并在此处添加一个链接? 谢谢,我修正了错误。这是糟糕的编码,显然,Binding ITEM-NAME .... 不好,我需要 Binding Path=ITEM-NAME, ...。这解决了我的错误(在这两种情况下仍然可以编译) @Poken1151 您还可以为 CultureAwareBinding 定义一个额外的构造函数,它将字符串作为唯一参数:public CultureAwareBinding(string path) : base(path) ConverterCulture = CultureInfo.CurrentCulture;
。这样你就不需要指定Path=…
。【参考方案3】:
在初始化任何 UI 之前放置以下代码行。这对我有用。
FrameworkElement.LanguageProperty.OverrideMetadata(typeof(FrameworkElement),
new FrameworkPropertyMetadata(XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)));
(并删除所有显式文化参数)
【讨论】:
就像一个魅力,只是一行代码,无需触及任何其他代码。我不明白,为什么这不是公认的答案以及为什么它的赞成票如此之少。有什么陷阱吗? 如问题中所述,设置语言只会导致 WPF 使用语言的默认日期/时间格式,而不是系统区域设置中选择的格式。 我已将此代码放入我的 App.xaml.cs Application_Startup 方法中并且运行良好。现在日期时间已正确格式化为我的系统区域设置。 @CollinK 它不仅适用于日期/时间格式,而且适用于其他区域设置,例如小数点分隔符(在许多系统的区域设置中,它不是点,而是逗号)。【参考方案4】:您的第二次尝试很接近,并引导我找到了一个对我有用的解决方案。
设置 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" />
【讨论】:
【参考方案5】:我使用该代码来满足我的需要。希望它能满足你的:-)! 如果不能“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>
【讨论】:
【参考方案6】:我想出了一个避免更新所有绑定的技巧/解决方法。将此代码添加到主窗口的构造函数中。
XmlLanguage language = XmlLanguage.GetLanguage("My-Language");
typeof(XmlLanguage).GetField("_compatibleCulture", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(language, CultureInfo.CurrentCulture);
this.Language = language;
由于它使用反射,因此无法保证它在将来会起作用,但现在可以(.NET 4.6)。
【讨论】:
【参考方案7】:我们可以使用 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)));
【讨论】:
【参考方案8】:后面的代码改一下语言怎么样?
this.Language = XmlLanguage.GetLanguage(Thread.CurrentThread.CurrentCulture.Name);
【讨论】:
此方法忽略“区域和语言”对话框中的自定义设置,只使用名称获取语言。 它是最简单的解决方案,对我也适用(Windows Phone 7)。 @Markus k:抱歉,没听懂你想说/解释的意思吗? @hfmobile 他的意思是,如果您在区域设置中选择一种语言(例如 German Germany),然后手动修改任何设置(例如 Short Date 更改为 dMyyyy),设置语言以上建议不会采用新格式。【参考方案9】:避免使用“this.Language = XmlLanguage.GetLanguage(Thread.CurrentThread.CurrentCulture.Name);”的问题不是一个真正的常见的。我不知道法国有任何用户会将日期格式更改为美国或日本格式,因为至少没有用户知道这样的更改是可能的(并且不知道该怎么做)...... 所以当然“语言=”并不完美,但是在多年的WPF和Silverlight实践中,我从来没有看到任何用户遇到过这种问题...... 所以我还是使用“Langage=”这个技巧,它很简单,100% 覆盖了真正的需求。 当然其他解决方案似乎更好,但没有必要(我看到一些实现与“语言=”解决方案相比远非完美)。
【讨论】:
@Olivier:简单地说“其他用户甚至不知道这样的选项”,“根据我多年的 WPF 和 Silverlight 知识,我最了解”,甚至声称任何人都知道人们的“真正的需要”是嚣张的。你对这个星球上近 99% 的人的偏好一无所知——就像所有其他开发人员都不知道一样。接受有需要并提供帮助。使用 YYYY-MM-DD 是一种我希望全世界都同意的日期格式,而不是使用他们的区域格式。恕我直言,“从大到小”比任何其他格式都更有用,尤其是在排序方面。以上是关于在 WPF 绑定中使用“真实”CultureInfo.CurrentCulture,而不是 IetfLanguageTag 中的 CultureInfo的主要内容,如果未能解决你的问题,请参考以下文章