WPF中的StringFormat本地化问题


112

在WPF 3.5SP1中,我在DataBindings中使用了最后一个功能StringFormat:

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

我面临的问题是日期始终以英语格式设置...尽管我的系统是法语格式?如何强制日期跟随系统日期?


14
3年内获得高度评价的问题,但未标记答案!到处都是悲伤的面孔。
Gusdor 2012年

Answers:


212
// 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中创建国际化向导


17
是的,这很烦人。+1
Szymon Rozga,2009年

2
谢谢您解决我的头痛。
Skurmedel

9
大。但是,如果区域性在应用程序的生命周期中发生更改,该怎么办(例如,用户可以在设置对话框中更改其首选区域性)。根据文档FrameworkElement.LanguageProperty.OverrideMetadata不能被多次调用(它会引发异常)
TJKjaer 2010年

1
@pengibot此解决方案对我有用。我正在使用.net 4 / C#/ WPF,并将代码放入OnStartup方法中。
比约恩

18
请注意,Run元素并非继承自FrameworkElement,因此,如果将日期等绑定到Run,则需要额外调用typeof(System.Windows.Documents.Run)
Mat Fergusson 2015年

90

定义以下xml名称空间:

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

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

该解决方案将立即使用正确的值更新您的Bindings,但是对于如此少见又无害的东西,似乎有很多代码。


4
优秀的!这很棒!我将它添加到需要它的几个地方没有问题。顺便说一句,您的示例缺少}
Johncl 2011年

3
优秀作品。太奇怪了,WPF默认使用美国英语,而不是当前的文化。
克里斯·亚当斯

12

我只是想补充一下,在大多数情况下,loraderon的回答非常有用。当我将以下代码行放入App.xaml.cs中时,TextBlocks中的日期将以正确的区域性进行格式化。

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's时,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:Static gl: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)

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


实际上,Run并非源自FrameworkElement。您可以尝试修改loraderon的答案,以针对Run(FrameworkContentElement)以及FrameworkElement重复其代码。
内森·菲利普斯

对于那些可能会想知道的人:xmlns:gl =“ clr-namespace:System.Globalization; assembly = mscorlib”
Igor Meszaros

11

只需将文化快捷方式插入顶级标签:

xml:lang="de-DE"

例如:

<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>

5
但这就像假设美国是“正确”文化一样糟糕。它应该从用户的机器上获取设置。
misnomer

非常感谢,这正是我想要的!如果WPF认为en-EN是任何情况下的正确文化,那么我可以自己定位。当我在开发速度一天之内的概念验证应用程序时,没有时间花很多时间去弄成一行代码,只是想让一个代码DatePicker完成工作,所以这个简单的解决方法得到了解决。我迅速回到正轨!
M463

对于我的情况而言,最好的答案是,终于寻找了年龄:)当然,这是正确的,无论您假设它是en-US还是de-DE ...人们总是对简单的解决方案有疑问-.-
MushyPeas

10

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

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

将区域性设置为当前区域性语言的默认区域性。但是评论是错误的。这样做使用目前的文化,因为你不会看到用户可能所做的任何定制,它永远是对语言的默认。

要通过自定义实际使用当前区域性,您需要将和ConverterCulture一起设置StringFormat

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

gl您的根元素定义为一个全局命名空间

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

如果您是通过代码而不是XAML来执行此操作,则如下所示:binding.ConverterCulture = System.Globalization.CultureInfo.CurrentCulture;
Metalogic,

8

如果您需要在程序运行时更改语言,则只需更改根元素上的Language属性(不确定是否具有即时作用或是否必须重新创建子元素,就我而言,至少可以奏效)

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

它确实会立即重新评估,但可悲的是必须为每个单独的rootelement(window)设置
Firo 2013年

6

切换本地化的完整代码也如下<Run />所示:

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

0

如果要在运行时更改区域性信息,则可以使用一种行为(请参见下文)

  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();
    }
}

0

如果您正在处理代码而不是XAML,则可以按以下方式设置ConverterCulture:

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

@KZeise表示感谢,指出了使用默认区域性定义与使用用户的自定义区域性定义之间的细微差别。


-3

使用标签(包括文化)而不是texblock

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.