#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 как первая операция в асинхронной задаче