StringFormat Localization issues in wpf

WpfDatetimeLocalization

Wpf Problem Overview


In WPF 3.5SP1 i use the last feature StringFormat in DataBindings:

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

The problem I face is that the date is always formatted in English...although my system is in French ? How can i force the date to follow system date?

Wpf Solutions


Solution 1 - Wpf

// 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)));

From Creating an Internationalized Wizard in WPF

Solution 2 - Wpf

Define the following xml namespace:

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

Now behold this fantastic fix:

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

I'm well aware this isn't a global fix and you will require it on each of your Bindings but surely that is just good XAML? As far as I'm aware, the next time the binding updates it will use the correct CultureInfo.CurrentCulture or whatever you have supplied.

This solution will immediately update your Bindings with the correct values but it seems like a lot of code for something so rare and innocuous.

Solution 3 - Wpf

I just wanted to add that loraderon's answer works great in most cases. When I put the following line of code in my App.xaml.cs, the dates in my TextBlocks are formatted in the correct culture.

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

I say 'most cases'.For example, this will work out of the box:

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

...but when using Run's in a TextBlock, the DateTime is formatted in the default culture.

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

For this to work, I needed Gusdor's answer, namely adding ConverterCulture={x:Static gl:CultureInfo.CurrentCulture} to the 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)

I hope this additional answer will be of use to someone.

Solution 4 - Wpf

Just insert the culture shortcut to the top-level tag:

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>

Solution 5 - Wpf

As already stated, XAML defaults to the invariant culture (en-US), and you can use

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

to set the culture to the default culture for the language of the current culture. But the comment is wrong; this does not use the current culture, as you will not see any customizations the user might have made, it will always be the default for the language.

To actually use the current culture with customizations, you will need to set the ConverterCulture together with the StringFormat, as in

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

with the gldefined as a global namespace in your root element

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

Solution 6 - Wpf

If you need to change the language while the program is running you can just change the Language property on your root element (im unsure if this has an instant effect or if the sub element have to be recreated, in my case this works at least)

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

Solution 7 - Wpf

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

Solution 8 - Wpf

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

Solution 9 - Wpf

If you are working on code rather than XAML, you can set the ConverterCulture as follows:

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

Kudos to @KZeise for pointing out the subtle difference between using the default culture definition and using the user's customized culture definition.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionjonathanView Question on Stackoverflow
Solution 1 - WpfloraderonView Answer on Stackoverflow
Solution 2 - WpfGusdorView Answer on Stackoverflow
Solution 3 - WpfDaniël TeunkensView Answer on Stackoverflow
Solution 4 - WpfGerrit HoreisView Answer on Stackoverflow
Solution 5 - WpfKZeiseView Answer on Stackoverflow
Solution 6 - WpfPeterView Answer on Stackoverflow
Solution 7 - WpfhabakukView Answer on Stackoverflow
Solution 8 - Wpfuser3173620View Answer on Stackoverflow
Solution 9 - WpfMetalogicView Answer on Stackoverflow