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.