Wpf 中的 StringFormat 本地化问题

在 WPF 3.5 SP1中,我使用了 DataBindings 中的最后一个特性 StringFormat:

     <TextBlock Text="{Binding Path=Model.SelectedNoteBook.OriginalDate, StringFormat='f'}"
FontSize="20" TextTrimming="CharacterEllipsis" />

我面临的问题是,日期总是用英文格式... ... 尽管我的系统是法文的?如何强制日期遵循系统日期?

51063 次浏览
// Ensure the current culture passed into bindings is the OS culture.
// By default, WPF uses en-US as the culture, regardless of the system settings.
FrameworkElement.LanguageProperty.OverrideMetadata(
typeof(FrameworkElement),
new FrameworkPropertyMetadata(
XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)));

来自 在 WPF 中创建国际化向导

如果你需要在程序运行时改变语言,你只需要改变根元素的 Language 属性(我不确定这是否有即时效果或者子元素是否需要重新创建,在我的例子中,这至少可以工作)

element.Language = System.Windows.Markup.XmlLanguage.GetLanguage(culture.IetfLanguageTag);

Define the following xml namespace:

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

现在看看这个奇妙的解决方案:

<TextBlock Text="{Binding Path=Model.SelectedNoteBook.OriginalDate, StringFormat='f', ConverterCulture={x:Static gl:CultureInfo.CurrentCulture}" FontSize="20"TextTrimming="CharacterEllipsis" />

我很清楚这不是一个全局修复程序,您将需要在每个绑定上使用它,但是可以肯定的是,这只是一个好的 XAML?据我所知,下次绑定更新时,它将使用正确的 CultureInfo.CurrentCulture或您提供的任何内容。

这个解决方案将立即使用正确的值 更新您的 Bindings,但似乎有很多代码用于如此罕见和无害的事情。

只需将区域性快捷方式插入到顶级标记:

xml:lang="de-DE"

e.g.:

<Window x:Class="MyApp"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xml:lang="de-DE"
Title="MyApp" Height="309" Width="497" Loaded="Window_Loaded">....</Window>

我只想补充一点,Loraderon的答案在大多数情况下都很有效。当我在 App.xaml.cs 中放入以下代码行时,TextBlock 中的日期将按照正确的区域性进行格式化。

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

我说的是“大多数情况下”,例如,这个方法可以灵活运用:

<TextBlock Text="{Binding Path=Date, StringFormat={}{0:d MMMM yyyy}}" />
--> "16 mei 2013" (this is in Dutch)

... 但是当在 TextBlock 中使用 Run 时,DateTime 是以默认区域性格式设置的。

<TextBlock>
<Run Text="Datum: " />
<Run Text="{Binding Path=Date, StringFormat={}{0:d MMMM yyyy}, Mode=OneWay}" />
</TextBlock>
--> "Datum: 16 may 2013" (this is in English, notice the
name of the month "may" vs. "mei")

为此,我需要 Gusdor的答案,即将 ConverterCulture = { x: Staticgl: CultureInfo.CurrentCulture }添加到绑定。

<TextBlock>
<Run Text="Datum: " />
<Run Text="{Binding Path=Date, StringFormat={}{0:d MMMM yyyy}, ConverterCulture={x:Static gl:CultureInfo.CurrentCulture}, Mode=OneWay}" />
</TextBlock>
--> "Datum: 16 mei 2013" (=Dutch)

我希望这个附加的答案对某些人有用。

If you want to change culture info at runtime, you could use a behavior (see below)

  public class CultureBehavior<TControl> : Behavior<TControl>
where TControl : FrameworkElement
{
private readonly IEventAggregator _eventAggregator;
private readonly Action<CultureInfo> _handler;


public CultureBehavior()
{
_handler = (ci) => this.AssociatedObject.Language = XmlLanguage.GetLanguage(ci.IetfLanguageTag);
_eventAggregator = IoC.Container.Resolve<IEventAggregator>();
}


protected override void OnAttached()
{
base.OnAttached();


_eventAggregator
.GetEvent<LanguageChangedEvent>()
.Subscribe(_handler);


_handler.Invoke(CultureInfo.CurrentCulture);
}


protected override void OnDetaching()
{
_eventAggregator
.GetEvent<LanguageChangedEvent>()
.Unsubscribe(_handler);


base.OnDetaching();
}
}

The full code to switch the localization also in elements like <Run /> is this:

Private Shared Sub SetXamlBindingLanguage()


'' For correct regional settings in WPF (e.g. system decimal / dot or comma)
Dim lang = System.Windows.Markup.XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)
FrameworkContentElement.LanguageProperty.OverrideMetadata(GetType(TextElement), New FrameworkPropertyMetadata(lang))
FrameworkContentElement.LanguageProperty.OverrideMetadata(GetType(DefinitionBase), New FrameworkPropertyMetadata(lang))
FrameworkContentElement.LanguageProperty.OverrideMetadata(GetType(FixedDocument), New FrameworkPropertyMetadata(lang))
FrameworkContentElement.LanguageProperty.OverrideMetadata(GetType(FixedDocumentSequence), New FrameworkPropertyMetadata(lang))
FrameworkContentElement.LanguageProperty.OverrideMetadata(GetType(FlowDocument), New FrameworkPropertyMetadata(lang))
FrameworkContentElement.LanguageProperty.OverrideMetadata(GetType(TableColumn), New FrameworkPropertyMetadata(lang))
FrameworkElement.LanguageProperty.OverrideMetadata(GetType(FrameworkElement), New FrameworkPropertyMetadata(lang))


End Sub

如前所述,XAML 默认为不变区域性(en-US) ,您可以使用

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

将区域性设置为当前区域性语言的默认区域性。但是注释是错误的; 这是 not使用的当前区域性,因为您将不会看到用户可能进行的任何自定义,它将始终是该语言的默认设置。

要将当前区域性实际用于自定义,需要将 ConverterCultureStringFormat一起设置,如

Text="{Binding Day, StringFormat='d', ConverterCulture={x:Static gl:CultureInfo.CurrentCulture}}"

使用根元素中定义为全局名称空间的 gl

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

如果使用的是代码而不是 XAML,可以将 ConverterCulture 设置如下:

binding.ConverterCulture = System.Globalization.CultureInfo.CurrentCulture;

值得称赞的是@KZeise 指出了使用默认区域性定义和使用用户自定义区域性定义之间的细微差别。