Как переключить текущую культуру MainThread из асинхронного контекста?

#c# #wpf #asynchronous #culture #executioncontext

#c# #wpf #асинхронный #Культура #executioncontext

Вопрос:

У меня есть старый 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
  

Поток культуры с асинхронным выполнением. Но он не возвращается глобально обратно. Если я вызываю:

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

Вывод:

 [1]CheckCulture_Click: de-DE
  

Все является MainThread. (ManagedThreadId=1)

.NET Framework 4.8

Как я могу переключить текущую культуру глобально, не зная контекста вызова?

Комментарии:

1. Каков ожидаемый результат при нажатии CheckCulture кнопки?

2. @TheodorZoulias да, для НАС. это была последняя установленная культура

Ответ №1:

В .NET Core эти свойства реализованы как AsyncLocal<T> ‘s, что вкратце означает, что любые обновления для них влияют только на текущий поток асинхронного управления, такой как async метод.

В зависимости от того, чего вы пытаетесь достичь, вы можете подумать о создании и настройке своих собственных статических CultureInfo свойств.

В .NET Framework 4.6 и более поздних версиях вы могли бы установить NoAsyncCurrentCulture переключатель на true в своем App.config , чтобы вернуть старое поведение:

 <?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>
  

Элемент <AppContextSwitchOverrides>

Изменения перенацеливания для миграции с .NET Framework 4.5 на 4.6

Комментарии:

1. Я уже пробовал флаг, но установил его с помощью кода (в Application_Startup). Почему-то это не сработало. Когда я устанавливаю его через App.config, кажется, это работает. Спасибо. Теперь я должен подумать о том, является ли этот флаг правильным решением, но так оно и есть, решения иногда даются с трудом.

2. Может быть, лучше, если я переключу культуру в dispatcher.InvokeAsync В связи с этим предложением: Приложения, затронутые этим изменением, могут обойти его, явно установив желаемую систему. Глобализация. CultureInfo.Текущая культура или система. Глобализация. CultureInfo.CurrentUICulture как первая операция в асинхронной задаче