Search code examples
c#.netwinformscultureinfo

c# winform CultureUICulture reverting to previous value unexpectedly


I have a basic Winform app (.Net 4.6) where the main Form consists of only one docked panel. The form acts as the screen manager and will change the screen by adding/removing custom UserControls to/from the panel.

To put it simply, I have a button in the processing screen where if you click on it, will trigger a simple callback:

private void langButton_Click(object sender, EventArgs e)
{
      ActionCallback?.Invoke(UserAction.BackToTitle);
}

This will call a method in the main form and eventually:

System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("en");

Now I have checked that the CurrentUICulture changes as expected but as soon as it goes back to the UserControl, which is after the invoke line, the CurrentUICulture magically reverts back to whatever it used to be before executing the delegate! (no other code changes the culture)

What's even more baffling is similar code for my title screen works fine. They both run on UI thread.

I have been searching online and also tried many things including locking the line that is changing the culture in case the value was cached or something but no luck.

Obviously a lot of code is omitted but that's the gist of it. I could purposely pass the culture back and assign it again but that would just be bad.

Anyone could shed some light on this behaviour and possibly suggest some solutions?

EDIT 1:

I think I have finally found the issue. The callback was something like this:

    private async void HandleUserAction(UserAction action)
            {
                switch (action)
                {
                    case UserAction.BackToTitle:
                        System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("en");
                       break;
                   //other cases omitted
                }
            }

I basically did a quick test and extracted this to another anonymous function but without the async :

screen.ActionCallback2 += (a) => { System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("en");};

and it finally works!

I am not sure if it is duplicate of the post below as I am already using .Net 4.6 or above but I have to do some more reading. Keep CurrentCulture in async/await

I won't answer my own question yet as I am still trying to grasp why this is happening, if anyone else can explain this, feel free to do so.

EDIT 2:

I found that the issue can be reproduced with the code below

    private async void button16_Click(object sender, EventArgs e)
    {
            //will revert back to previous value once it exits the function
        System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("jp");
    
    }
            
    private void button15_Click(object sender, EventArgs e)
    {
                //it will be changed to jp
         System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("jp");
         Task.Run(() =>
         {
            this.Invoke((MethodInvoker)delegate
            {
                    //this will be changed back to jp after exiting the thread, even though its same UI thread
                  System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("en");
            });
         });
     }

Solution

  • In the end I fixed it by adding this to my app.config

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

    Though it is still a little strange to me especially when the function button15_Click doesn't involve async.