C# 如何从异步上下文切换主线程的CurrentCulture?

C# 如何从异步上下文切换主线程的CurrentCulture?,c#,wpf,asynchronous,culture,executioncontext,C#,Wpf,Asynchronous,Culture,Executioncontext,我有一个旧的API,以这种方式切换当前的文化: private void ChangeCulture(int lcid) { Debug.WriteLine($"[{Thread.CurrentThread.ManagedThreadId}] ChangeCulture Culture Start: {Thread.CurrentThread.CurrentCulture}"); var newCulture = CultureInf

我有一个旧的API,以这种方式切换当前的文化:

private void ChangeCulture(int lcid)
    {
        Debug.WriteLine($"[{Thread.CurrentThread.ManagedThreadId}] ChangeCulture Culture Start: {Thread.CurrentThread.CurrentCulture}");

        var newCulture = CultureInfo.GetCultureInfo(lcid);

        Debug.WriteLine($"[{Thread.CurrentThread.ManagedThreadId}] Changing culture of currentThread to: {newCulture}");

        Thread.CurrentThread.CurrentCulture = newCulture;
        Thread.CurrentThread.CurrentUICulture = newCulture;

        // Old framework compatibility (not important for this example)
        CultureInfo.DefaultThreadCurrentCulture = newCulture;
        CultureInfo.DefaultThreadCurrentUICulture = newCulture;

        Debug.WriteLine($"[{Thread.CurrentThread.ManagedThreadId}] ChangeCulture Culture End: {Thread.CurrentThread.CurrentCulture}");
    }
以前,代码是从同步上下文调用的。但是,因为现在需要从异步上下文调用代码。就像这里:

private async void Button_Click(object sender, RoutedEventArgs e)
    {
        Debug.WriteLine($"[{Thread.CurrentThread.ManagedThreadId}]Culture Start: {Thread.CurrentThread.CurrentCulture}");
        if (this.currrentLcid == 1031)
        {
            await Task.Delay(1000);
            this.ChangeCulture(1033);
            this.currrentLcid = 1033;
        }
        else
        {
            await Task.Delay(1000);
            this.ChangeCulture(1031);
            this.currrentLcid = 1031;
        }

        Debug.WriteLine($"[{Thread.CurrentThread.ManagedThreadId}]Culture End: {Thread.CurrentThread.CurrentCulture}");
    }
输出:

[1]Culture Start: de-DE
[1] ChangeCulture Culture Start: de-DE
[1] Changing culture of currentThread to: en-US
[1] ChangeCulture Culture End: en-US
[1]Culture End: en-US
[1]CheckCulture_Click: de-DE
使用异步执行的区域性流。但它不会在全球范围内回流。如果我打电话:

    private void CheckCulture_Click(object sender, RoutedEventArgs e)
    {
        Debug.WriteLine($"[{Thread.CurrentThread.ManagedThreadId}]CheckCulture_Click: {Thread.CurrentThread.CurrentCulture}");
    }
输出:

[1]Culture Start: de-DE
[1] ChangeCulture Culture Start: de-DE
[1] Changing culture of currentThread to: en-US
[1] ChangeCulture Culture End: en-US
[1]Culture End: en-US
[1]CheckCulture_Click: de-DE
一切都是主线。(ManagedThreadId=1)

.NET Framework 4.8


如何在不知道调用上下文的情况下全局切换当前区域性?

在.NET Core中,这些属性被实现为
AsyncLocal
,简而言之,这意味着对它们的任何更新只会影响当前的异步控制流,例如
async
方法

根据您所要完成的任务,您可以考虑创建并设置自己的静态<代码> CultualFiels属性>

在.NET Framework 4.6及更高版本上,您可以在
App.config
中将
NoAsyncCurrentCulture
开关设置为
true
,以恢复旧的行为:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <startup> 
      <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8"/>
  </startup>
  <runtime>
    <AppContextSwitchOverrides value="Switch.System.Globalization.NoAsyncCurrentCulture=true"/>
  </runtime>
</configuration>


单击
检查文化
按钮时的预期结果是什么?@TheodorZoulias yes,en US。这是cultureI已经尝试过的最后一组标志,但它是通过代码设置的(在应用程序启动时)。不知怎的,这不起作用。当我通过App.config设置它时,它似乎可以工作。谢谢现在我必须考虑这个标志是否是正确的解决方案,但事实就是如此,决策有时很难。如果我在dispatcher.invokeAsync中切换区域性,可能会更好。与此句子相关:受此更改影响的应用程序可以通过显式设置所需的System.Globalization.CultureInfo.CurrentCulture或System.Globalization.CultureInfo.CurrentUICulture作为异步中的第一个操作来解决此问题任务