Home > front end >  Setting Culture in .net5 WPF application
Setting Culture in .net5 WPF application

Time:12-02

In a WPF application I try to set the culture in OnStartup.

    protected override async void OnStartup(StartupEventArgs startupEventArgs)
    {
        base.OnStartup(startupEventArgs);
        var a = new CultureInfo(ConfigurationManager.AppSettings["Language"]);
        Thread.CurrentThread.CurrentCulture = a;
        Thread.CurrentThread.CurrentUICulture = a;            
        CultureInfo.DefaultThreadCurrentCulture = a
        CultureInfo.DefaultThreadCurrentUICulture = a;
        CultureInfo.CurrentCulture = a;
    }

If I start a method from the MainWindow with Click event or with ICommand then in the method the Thread.CurrentThread.CurrentUICulture will be always en-US, which is very strange (can sombody exaplain?). I can set again to the desired Culture but I have to do it in each called method one by one. Is there an alternative?

In .net4.7 there was a workaround but it does not work in .net5.

CodePudding user response:

As it correctly pointed in comment it will work without async, with async you need to do it on the applicaton's thread. The key is, that CultureInfo.CurrentCulture set the value for current thread and as it's a thread pool you doesn't see it in async event handler, or I suppose you can have it occasionally, if you will get the same thread.

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

    await Application.Current.Dispatcher.BeginInvoke((Action)(() =>
    {
        var a = new CultureInfo(ConfigurationManager.AppSettings["Language"]);
        Thread.CurrentThread.CurrentCulture = a;
        Thread.CurrentThread.CurrentUICulture = a;

        CultureInfo.DefaultThreadCurrentCulture = a;
        CultureInfo.DefaultThreadCurrentUICulture = a;
        CultureInfo.CurrentCulture = a;
    }
    ));
}

CodePudding user response:

The reason for this behavior is how async methods are implemented. async methods have their own special execution context. This context has it's own CultureInfo, which is inherited from the thread that invokes the async method.
In your case, the async context's culture is inherited from the main thread, before the culture is changed.

What you can do is to implement the already suggested solution using the Dispatcher.InvokeAsync to postpone the CultureInfo configuration. This way the configuration is executed outside the async context:

Dispatcher.InvokeAsync(() => CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo("en-EN"));

Since this can mess up your initialization routine, as the real context would be avaailable after the application is configured and the main Window displayed, you would prefer a different solution.

You can for example used an event based initialization routine, where you run low-level application configuration like culture configuration first and continue with the remaining initialization that involves asynchronous operations in an async context:

App.xaml.cs

// Event may be defined on a different class
private event EventHandler ConfigurationCompleted;
private void OnConfigurationCompleted() => this.ConfigurationCompleted?.Invoke(this, EventArgs.Empty);

protected override void OnStartup(StartupEventArgs startupEventArgs)
{
  this.ConfigurationCompleted  = ConfigureInAsyncContext;

  // Do "low-level" application configuration. Code may be executed in a different class context

  CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo("en-EN");

  ...

  // Continue in async context
  OnConfigurationCompleted();
}
 
private async void ConfigureInAsyncContext(object sender, EventArgs e)
{
  // TODO::Execute async operations

  new MainWindow().Show();
} 

The key is to separate the non async configuration from the async initialization.

  • Related