124

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?

Pavel Anikhouski
  • 21,776
  • 12
  • 51
  • 66

9 Answers9

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

Thomas Levesque
  • 286,951
  • 70
  • 623
  • 758
loraderon
  • 4,658
  • 2
  • 32
  • 35
  • 18
    Yea this is quite annoying. +1 – Szymon Rozga Feb 06 '09 at 15:56
  • 2
    Thank you for resolving my headache. – Skurmedel May 12 '10 at 15:41
  • 9
    Great. But what to do if the culture changes during the lifecycle of the application (e.g. the user can change his preferred culture in a settings dialog). According to the documentation FrameworkElement.LanguageProperty.OverrideMetadata cannot be called more than once (it throws an exception) – Torben Junker Kjær Oct 28 '10 at 08:45
  • 1
    @pengibot This solution works for me. I'm using .net 4/C#/WPF and I put the code in the OnStartup method. – Björn Jun 13 '13 at 11:29
  • 21
    Note that the **Run** element does not inherit from **FrameworkElement**, so if you bind dates etc. to a **Run** then you will need an extra call for **typeof(System.Windows.Documents.Run)** – Mat Fergusson Jan 07 '15 at 13:49
  • This doesn't work for converting to local timezone. My DateTime values are coming in from the database as UTC time. I tried this solution hoping it would auto-magically convert all DateTime bindings to the current OS timezone, but nothing changed. – Dennis W Nov 17 '16 at 11:24
  • 1
    If you investigate all the answers here, another pitfall with this answer becomes evident: if the user customizes their culture (e.g. use es-ES but change the short date format from `dd/MM/yyyy` to `d/M/yyyy`) this solution does not honor the customizations. You need to use `ConverterCulture={x:Static gl:CultureInfo.CurrentCulture}` on your bindings to correct for this, unfortunately. – Guttsy Feb 23 '17 at 17:04
97

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.

Nightfirecat
  • 11,432
  • 6
  • 35
  • 51
Gusdor
  • 14,001
  • 2
  • 52
  • 64
  • 5
    Excellent! This worked wonderfully! I have no problem adding this to the few places where its needed. Btw your example is missing a } – Johncl Dec 13 '11 at 11:49
  • 4
    Excellent work. It's so weird that WPF uses US-English by default, as opposed to the current culture. – Kris Adams Aug 07 '15 at 10:24
14

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.

Daniël Teunkens
  • 379
  • 3
  • 13
  • Indeed, Run does not derive from FrameworkElement. You could try modifying loraderon's answer to repeat his code for the base of Run (FrameworkContentElement) as well as for FrameworkElement. – Nathan Phillips Nov 26 '13 at 17:25
  • For those who might wonder: xmlns:gl="clr-namespace:System.Globalization;assembly=mscorlib" – Igor Meszaros Mar 31 '17 at 16:12
12

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>
Gerrit Horeis
  • 541
  • 5
  • 14
  • 5
    But this is just as bad as assuming that en-US is the 'Correct' culture. It should rather take the settings from the user's machine. – misnomer Jun 17 '13 at 21:49
  • Thank you very much, this was exactly what I was looking for! If WPF thinks that en-EN is the correct culture for any situation, so can I with my own localization. As I'm working on a proof-of-concept application where development speed is the order of the day, there is no time to mess around with dozens of code lines just to get a single `DatePicker` to do it's job, so this easy fix got me quickly back on track! – M463 Jul 10 '15 at 14:25
  • 1
    best answer for my case, finally been looking for ages :) and of course it's correct, either you assume its en-US or it's de-DE... people always have problems with simple solutions -.- – MushyPeas Nov 01 '15 at 20:50
  • Well, I wanted to override the system culture, that's perfect; and I may add that it works in any markup and propagages to all children, it does not have to be the top one (Window, UserControl, etc). – Soleil Dec 19 '20 at 03:30
12

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"
KZeise
  • 123
  • 1
  • 5
  • If you are doing this through code instead of XAML it's as follows: `binding.ConverterCulture = System.Globalization.CultureInfo.CurrentCulture;` – Metalogic Jan 29 '18 at 04:32
8

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);
Peter
  • 37,042
  • 39
  • 142
  • 198
  • it does immediatly reevaluate but sadly has to be set for each and every rootelement(window) seperate – Firo Sep 26 '13 at 12:33
7

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
habakuk
  • 2,712
  • 2
  • 28
  • 47
0

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

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.

Metalogic
  • 498
  • 6
  • 16