C# 使用「;“真正的”;CultureInfo.CurrentCulture位于WPF绑定中,而不是IETGatag中的CultureInfo
就我而言: 我有一个TextBlock绑定到DateTime类型的属性。 我希望它显示为用户所说的区域设置C# 使用「;“真正的”;CultureInfo.CurrentCulture位于WPF绑定中,而不是IETGatag中的CultureInfo,c#,wpf,binding,currentculture,C#,Wpf,Binding,Currentculture,就我而言: 我有一个TextBlock绑定到DateTime类型的属性。 我希望它显示为用户所说的区域设置 <TextBlock Text="{Binding Date, StringFormat={}{0:d}}" /> 但是使用这行代码,它只是将文本显示为CultureInfo的默认格式 CurrentCulture的IetfLanguageTag表示,与系统区域设置中选择的有效值不同: (例如,对于“de de”dd.MM.yyyyy用于代替所选的yyyy-MM-dd) 有
<TextBlock Text="{Binding Date, StringFormat={}{0:d}}" />
但是使用这行代码,它只是将文本显示为CultureInfo的默认格式
CurrentCulture的IetfLanguageTag表示,与系统区域设置中选择的有效值不同:
(例如,对于“de de”dd.MM.yyyyy用于代替所选的yyyy-MM-dd)
有没有一种方法可以使绑定使用正确的格式而不在每个绑定上定义ConverterCulture
编码
string.Format("{0:d}",Date);
使用正确的区域性设置
编辑:
另一种不按预期工作的方式(如.Language=…所做的):
及
您可以创建绑定的子类(例如CultureWareBinding),该子类在创建时将ConverterCulture自动设置为当前区域性
这不是一个完美的解决方案,但可能是唯一的解决方案,因为追溯性地强制绑定尊重文化可能会破坏WPF中依赖于此行为的其他代码
如果你需要更多的帮助,请告诉我 您的第二次尝试很接近,并引导我找到了一个对我来说确实有效的解决方案 设置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”)
如何更改代码后面的Lanague
this.Language = XmlLanguage.GetLanguage(Thread.CurrentThread.CurrentCulture.Name);
这是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) CultureWareBinding的实际使用
<Textblock Text="{myWpfLib:CultureAwareBinding Path=Salary, Source=Contact, StringFormat={}{0:C}}" />
避免使用“this.Language=XmlLanguage.GetLanguage(Thread.CurrentThread.CurrentCulture.Name);”的问题其实并不常见。我不知道法国的任何用户会将日期格式更改为美国或日本格式,只是因为至少没有用户知道这样的更改是可能的(并且不知道如何做)。。。 因此,“language=”当然不是完美的,但在多年的WPF和Silverlight实践中,我从未发现任何用户存在此类问题。。。 所以我仍然使用“Langage=”技巧,它很简单,涵盖了100%的实际需求。
当然,其他解决方案似乎更好,但不需要(我看到一些实现与“language=”solution相比远远不够完美)。我使用这些代码,并根据自己的需要获得适当的结果。希望它能填满你的:-)! 如果不能“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)。在初始化任何UI之前,请先输入以下代码行。这对我有用
FrameworkElement.LanguageProperty.OverrideMetadata(typeof(FrameworkElement),
new FrameworkPropertyMetadata(XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)));
(并删除所有显式区域性参数)我们可以使用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)));
}
//
///集合培养
///
私有void SetCulture(){
var newCulture=newcultureinfo(“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(类型为(FrameworkElement)),新FrameworkPropertyMetadata(
System.Windows.Markup.XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag));
}
查看以下内容:@Pavlo:此问题的答案还使用IetfLanguageTag获取文化信息。谢谢您的回答。这个解决方案听起来像是唯一一个可能的解决方案。“因为追溯性地强制绑定尊重文化可能会破坏WPF中依赖于这种行为的其他代码。”-我认为,从长远来看,继续保持这种破坏的行为比引入短期中断更糟糕。或者,他们可以修复它,但使用.NET的程序集绑定功能来检测应用程序何时需要较旧的版本,并为其维护已损坏的行为。这个bug在WPF中已经存在了12年,而且他们没有自己的CultureAwareBinding
内置,这真是太疯狂了。这个方法忽略了“区域和语言”对话框中的自定义设置,只使用名称来获取语言。这是最简单的解决方案,对我来说也很好(Windows Phone 7)@Markus k:对不起,没听清楚你想说什么/解释什么?@hfmobile他的意思是,如果你在区域设置(德国除外)中选择一种语言,然后手动修改任何设置(例如短日期更改为d.M.yyyy),则设置上述建议的语言将不会生效
FrameworkElement.LanguageProperty.OverrideMetadata(typeof(FrameworkElement),
new FrameworkPropertyMetadata(XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)));
[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();
}
}
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)));
}