Search code examples
c#.netwpftaskcultureinfo

WPF - Change UI culture in callback of asynchrone task


In my application, the user can switch the language. Before the change is apply, a check is done. In full synchronous this work fine.

Now, the check is asynchronous and a callback on the UI thread set CultureInfo.CurrentUICulture. But at the end of callback, the CultureInfo.CurrentUICulture is rollback. See this example :

MainWindow.xaml :

<StackPanel>
    <ComboBox SelectionChanged="ComboBox_Selected">
        <ComboBoxItem>en-US</ComboBoxItem>
        <ComboBoxItem>en-GB</ComboBoxItem>
        <ComboBoxItem>fr-FR</ComboBoxItem>
    </ComboBox>
    <Button Click="Button_Click">Display</Button>
</StackPanel>

MainWindow.xaml.cs :

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void ComboBox_Selected(object sender, RoutedEventArgs e)
    {
        Debug.WriteLine($"A - {Thread.CurrentThread.ManagedThreadId} - {Thread.CurrentThread.IsBackground}");
        var to = ((ComboBoxItem)((ComboBox)sender).SelectedItem).Content as string;
        Task.Delay(TimeSpan.FromSeconds(1)).ContinueWith(
            t => SetCurrentCulture(to),
            TaskScheduler.FromCurrentSynchronizationContext()
        );
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        MessageBox.Show(CultureInfo.CurrentCulture.Name);
    }

    private static void SetCurrentCulture(string to)
    {
        Debug.WriteLine($"B - {Thread.CurrentThread.ManagedThreadId} - {Thread.CurrentThread.IsBackground}");
        var culture = new CultureInfo(to);
        CultureInfo.DefaultThreadCurrentCulture = culture;
        CultureInfo.DefaultThreadCurrentUICulture = culture;
        CultureInfo.CurrentCulture = culture;
        CultureInfo.CurrentUICulture = culture;
    }
}

Can you explain why? How can resolve this?


Solution

  • Can you explain why?

    From the docs:

    For apps that target the .NET Framework 4.6 or later versions, culture is part of an asynchronous operation's context. In other words, starting with apps that target the .NET Framework 4.6, asynchronous operations by default inherit the values of the CurrentCulture and CurrentUICulture properties of the thread from which they are launched.

    How can resolve this?

    Add the following switch to your App.config file to switch back to the behaviour seen in .NET Framework 4.5.2:

    <runtime>
        <AppContextSwitchOverrides value="Switch.System.Globalization.NoAsyncCurrentCulture=true" />
    </runtime>