在 .net5 WPF 应用程序中设置区域性
Setting Culture in .net5 WPF application
在 WPF 应用程序中,我尝试在 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;
}
如果我使用 Click
事件或 ICommand
从 MainWindow
开始方法,那么在方法中 Thread.CurrentThread.CurrentUICulture
将始终是 en-US
,这很奇怪(有人可以解释吗?)。我可以再次设置为所需的 Culture
但我必须在每个调用的方法中一一进行。有其他选择吗?
在 .net4.7 中有一个 但它在 .net5 中不起作用。
正如它在评论中正确指出的那样,它可以在没有 async
的情况下工作,而使用 async
您需要在应用程序的线程上进行。关键是,CultureInfo.CurrentCulture
设置了 current 线程的值,因为它是一个线程池,你在 async
事件处理程序中看不到它,或者我想你可以偶尔拥有它,如果你会得到相同的线程。
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;
}
));
}
此行为的原因在于 async
方法的实现方式。 async
方法有自己特殊的执行上下文。此上下文有它自己的 CultureInfo
,它继承自调用 async
方法的非异步上下文。
在您的情况下,async
上下文的文化是从主线程继承的,在 文化改变之前。
您可以执行已建议的解决方案,使用 Dispatcher.InvokeAsync
推迟 CultureInfo 配置。这样配置在 async
上下文之外执行:
Dispatcher.InvokeAsync(() => CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo("en-EN"));
由于这可能会打乱您的初始化例程,因为在配置应用程序并显示主要 Window 后,真实的上下文将可用,因此您会更喜欢不同的解决方案。
例如,您可以使用基于事件的初始化例程,其中您 运行 首先进行文化配置等低级应用程序配置,然后继续进行涉及 async
上下文中的异步操作的其余初始化:
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();
}
关键是将非异步配置与异步初始化分开。
在 WPF 应用程序中,我尝试在 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;
}
如果我使用 Click
事件或 ICommand
从 MainWindow
开始方法,那么在方法中 Thread.CurrentThread.CurrentUICulture
将始终是 en-US
,这很奇怪(有人可以解释吗?)。我可以再次设置为所需的 Culture
但我必须在每个调用的方法中一一进行。有其他选择吗?
在 .net4.7 中有一个
正如它在评论中正确指出的那样,它可以在没有 async
的情况下工作,而使用 async
您需要在应用程序的线程上进行。关键是,CultureInfo.CurrentCulture
设置了 current 线程的值,因为它是一个线程池,你在 async
事件处理程序中看不到它,或者我想你可以偶尔拥有它,如果你会得到相同的线程。
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;
}
));
}
此行为的原因在于 async
方法的实现方式。 async
方法有自己特殊的执行上下文。此上下文有它自己的 CultureInfo
,它继承自调用 async
方法的非异步上下文。
在您的情况下,async
上下文的文化是从主线程继承的,在 文化改变之前。
您可以执行已建议的解决方案,使用 Dispatcher.InvokeAsync
推迟 CultureInfo 配置。这样配置在 async
上下文之外执行:
Dispatcher.InvokeAsync(() => CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo("en-EN"));
由于这可能会打乱您的初始化例程,因为在配置应用程序并显示主要 Window 后,真实的上下文将可用,因此您会更喜欢不同的解决方案。
例如,您可以使用基于事件的初始化例程,其中您 运行 首先进行文化配置等低级应用程序配置,然后继续进行涉及 async
上下文中的异步操作的其余初始化:
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();
}
关键是将非异步配置与异步初始化分开。