在 .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 事件或 ICommandMainWindow 开始方法,那么在方法中 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();
} 

关键是将非异步配置与异步初始化分开。