6

I'm based in the UK, and my computer always shows a UK date format (dd/mm/yyyy).

My WPF project is, for some reason converting my DateTime format to US type. This occurs on my work machine and home machine.

I've been able to replicate the issue very simply

<Window x:Class="TimeIssues.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <TextBlock Text="{Binding MyTime}"></TextBlock> <!-- the value is 1/28/2014 10:15:37 (note it is M/dd/yyyy....)
</Grid>
</Window>

And in the code behind, simply

public partial class MainWindow : Window
{
    public MainWindow()
    {
        SetMyTime("28/01/2014 10:15:37"); //note, this is dd/MM/yyyy .... format
        this.DataContext = this;
        InitializeComponent();
    }

    private void SetMyTime(string dateTime)
    {
        DateTime dt;
        DateTime.TryParseExact(dateTime, "dd/MM/yyyy HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.None, out dt);
        MyTime = dt; // the value is expected, showing 28/01/2014 10:15:37
    }

    public DateTime MyTime { get; set; }
}

Just to confirm that this isn't an IT issue (or so I think), my PC is set for UK (and the Location is also set to UK as is the Current language for non-unicode programs)

enter image description here

I have read WPF format DateTime in TextBlock? but this won't help (I don't think) as that question is about setting the format when the format is known.

If I update my MyTime from DateTime to a string, then the result is expected (UK format)! The issue is WPF changes the format when the type is DateTime which is not desired!

My issue is 2 fold -

  1. I won't know the format the user needs (my software is distributed world wide).
  2. WPF appears to change the format incorrectly any way!

How do I tell WPF to use the user's locale settings? Is there any way to read the OS settings (as per the screen shot above)?

Community
  • 1
  • 1
Dave
  • 8,163
  • 11
  • 67
  • 103

2 Answers2

9

CultureInfo is picked from Thread's current culture which in your case will be set to en-US. You need to set it to en-GB like this:

Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo("en-GB");

But when you set this you will see, XAML doesn't pick this. For XAML to pick it you have to override FrameworkElement.LanguageProperty metadata.

Override OnStartup() method in your App.xaml.cs and place this code there and you are good to go:

protected override void OnStartup(StartupEventArgs e)
{
   base.OnStartup(e);

   Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("en-GB");
   Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo("en-GB");

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

UPDATE

Is there any way to read the OS settings (as per the screen shot above)?

In case you want to pick CultureInfo based on the format selected for system, you can do that as well by getting LCID for OS. This is how you do it:

[DllImport("kernel32.dll")]
private static extern int GetUserDefaultLCID();

protected override void OnStartup(StartupEventArgs e)
{
   base.OnStartup(e);

   int machineLCID = GetUserDefaultLCID();
   CultureInfo machineCultureInfo = CultureInfo.GetCultureInfo(machineLCID);
   Thread.CurrentThread.CurrentUICulture = machineCultureInfo;
   Thread.CurrentThread.CurrentCulture = machineCultureInfo;

   FrameworkElement.LanguageProperty.OverrideMetadata(
                typeof(FrameworkElement),
                new FrameworkPropertyMetadata(
           XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)));
}
Rohit Vats
  • 79,502
  • 12
  • 161
  • 185
  • Thank you again Rohit, but, my issue is more that WPF changes the format. The software I am working on is distributed world wide, and therefore setting it explicitly to en-GB isn't going to work :( – Dave Mar 15 '14 at 15:12
  • So from where you want to pick the culture from? Some config file or system's language? – Rohit Vats Mar 15 '14 at 15:14
  • I'm hoping the system's language. As per my screen shot, the OS let's us set the format we want so I would have hoped that information is available to use? Something like (pseudo code) `DateTime.TryParse(currentTime, SystemDateFormat, out result)`. Or is this wishful thinking and not the 'standard way' – Dave Mar 15 '14 at 15:16
  • @Dave Rook - Yeah you can do that. See the update in answer for that. – Rohit Vats Mar 15 '14 at 16:09
  • @DaveRook - Does that work for you OR still looking for something else? – Rohit Vats Mar 17 '14 at 08:02
  • I'm sorry for late reply, alas, it does not. I copied the code and pasted it into the app file. I can see it's working and correctly reports `en-GB`. Yet, when I bind my `DateTime` to a `textblock` the same issue persists. In debug, I can see the value is 28/01/2014... but in my WPF GUI it shows as 01/28/2014 .... – Dave Mar 17 '14 at 14:54
  • Have you placed the code in `OnStartup()`? Works completely fine at my end. – Rohit Vats Mar 17 '14 at 15:02
  • The issue is, my MainWindow is called directly from another project. The app.xaml.cs is never called - I even added an empty constructor, stuck on a break - nothing. So, I've hacked it in, and so far, looking good. I've had to do `public MainWindow() { OnStartup(); InitializeComponent(); }` – Dave Mar 17 '14 at 15:02
  • This should be called when actual instance of `MainWindow` is created. If App is not a way, I would suggest to create a static constructor of MainWindow and place the above code there. And yeah placing it above InitializeComponent will work as well because XAML is not rendered yet. – Rohit Vats Mar 17 '14 at 15:04
  • The MainWindow is created from another project `var mainWindow = new OtherClassLibrary.UI.MainWindow(); mainWindow.ShowDialog();` - The code is inherited! However, using your code as I said earlier worked perfectly. Once again, you've solved yet another issue for me, thank you. – Dave Mar 17 '14 at 15:06
  • No issue from wherever it's called. Static constructor will run first always before instance constructor runs. You're welcome Dave..!! :) – Rohit Vats Mar 17 '14 at 15:07
0

Try something like <TextBlock Text="{Binding MyTime, ConverterCulture='en-GB'} </TextBlock>.

If that fails try <TextBlock Text="{Binding MyTime, ConverterCulture='en-GB', StringFormat={}{0:dd/MM/yyyy} </TextBlock>

One thing you might try is instead of returning a DateTime object, try making your class get/set a formatted string based on the current CultureInfo of the system running the program. This would bind the string the way you want it instead of the default DateTime binding of en-US.

Newyork167
  • 494
  • 5
  • 9