【问题标题】:StringFormat Localization issues in wpfwpf中的StringFormat本地化问题
【发布时间】:2010-10-05 22:16:34
【问题描述】:

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

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

我面临的问题是日期总是用英文格式化...虽然我的系统是法文的?如何强制日期跟随系统日期?

【问题讨论】:

  • 3 年一个高度评价的问题,但没有标记答案!到处都是悲伤的面孔。

标签: wpf datetime localization


【解决方案1】:
// 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)));

来自Creating an Internationalized Wizard in WPF

【讨论】:

  • 是的,这很烦人。 +1
  • 感谢您解决了我的头痛问题。
  • 太棒了。但是如果文化在应用程序的生命周期中发生变化该怎么办(例如,用户可以在设置对话框中更改他喜欢的文化)。根据文档 FrameworkElement.LanguageProperty.OverrideMetadata 不能多次调用(它会引发异常)
  • @pengibot 这个解决方案对我有用。我正在使用 .net 4/C#/WPF,并将代码放在 OnStartup 方法中。
  • 请注意,Run 元素不继承自 FrameworkElement,因此如果将日期等绑定到 Run那么您将需要额外调用 typeof(System.Windows.Documents.Run)
【解决方案2】:

定义以下 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" />

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

This solution will immediately update your Bindings with the correct values 但对于如此稀有和无害的东西来说,似乎有很多代码。

【讨论】:

  • 太棒了!这非常有效!我可以毫无问题地将它添加到它需要的几个地方。顺便说一句,您的示例缺少 }
  • 出色的工作。 WPF 默认使用美国英语,而不是当前的文化,这太奇怪了。
【解决方案3】:

我只是想补充一点,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} 添加到 Binding。

<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"
【解决方案4】:

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

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>

【讨论】:

  • 但这与假设 en-US 是“正确”文化一样糟糕。它应该从用户的机器中获取设置。
  • 非常感谢,这正是我想要的!如果 WPF 认为 en-EN 在任何情况下都是正确的文化,那么我也可以使用自己的本地化。由于我正在开发一个概念验证应用程序,其中开发速度是当务之急,因此没有时间为了获得单个 DatePicker 来完成它的工作而处理数十行代码行,所以这个简单的修复让我很快回到正轨!
  • 我的情况的最佳答案,终于一直在寻找年龄 :) 当然它是正确的,无论你假设它是 en-US 还是 de-DE ......人们总是对简单的解决方案有问题 - .-
  • 嗯,我想覆盖系统文化,这很完美;我可以补充一点,它适用于所有子项的任何标记和传播,它不必是最重要的(Window、UserControl 等)。
【解决方案5】:

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

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

将文化设置为当前文化语言的默认文化。但是评论是错误的;这使用当前文化,因为您不会看到用户可能进行的任何自定义,它始终是语言的默认值。

要实际使用当前的文化和自定义,您需要将ConverterCultureStringFormat 一起设置,如

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;
【解决方案6】:

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

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

【讨论】:

  • 它确实会立即重新评估,但遗憾的是必须为每个根元素(窗口)单独设置
【解决方案7】:

&lt;Run /&gt; 等元素中切换本地化的完整代码如下:

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

【讨论】:

    【解决方案8】:

    如果您想在运行时更改文化信息,您可以使用行为(见下文)

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

    【讨论】:

      【解决方案9】:

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

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

      感谢@KZeise 指出使用默认文化定义和使用用户自定义文化定义之间的细微差别。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-04-19
        • 1970-01-01
        • 2018-11-22
        • 2011-05-28
        • 2012-04-02
        • 2010-10-22
        • 1970-01-01
        相关资源
        最近更新 更多