C# Corner

.NET Framework 4.5 Multi-Threaded Globalization

Eric Vogel shows you how to use the CultureInfo API in .NET Framework 4.5 to simplify localization in a multi-threaded application.

The .NET Framework 4.5 includes a simplified way of setting the default culture and UI culture for an application domain. In .NET Framework 4 and earlier frameworks, if you wanted to set the Culture and UI Culture for an application, you’d typically set the culture settings on the current Thread. A small problem arose if you created multiple threads, however. By default, a new Thread will use the user’s preferred culture setting. To assign a different culture, you’d have change the culture of the Thread after creating it, or pass in the CultureInfo using a ParameterizedThreadStart constructed Thread.

To demonstrate how to conquer this conundrum, let's create a Windows Presentation Foundation C# sample application using .NET Framework 4. The UI for the demo application will display the user’s preferred culture as well as the UI culture for the newly created Threads and Task. Open up the MainWindow.xaml, and add the markup from the following code into the root <Grid> element:

<StackPanel>
    <TextBlock>User's Preferred Culture</TextBlock>
    <TextBlock Name="UserPreferredCulture" Text="{Binding DisplayName}"></TextBlock>
    <TextBlock>New Thread Parameter UI Culture</TextBlock>
    <TextBlock Name="ThreadUIParamCulture" Text="{Binding DisplayName}"></TextBlock>
    <TextBlock>New Thread Property UI Culture</TextBlock>
    <TextBlock Name="ThreadUIPropCulture" Text="{Binding DisplayName}"></TextBlock>
    <TextBlock>New Task UI Culture</TextBlock>
    <TextBlock Name="TaskUICulture" Text="{Binding DisplayName}"></TextBlock>
</StackPanel>

The cultureParameterized Thread uses a ParameterizedThreadStart setting, to pass the CultureInfo to the Thread, when it's started. The cultureAfter thread is constructed using ThreadStart. The CurrentCulture and CurrentUICulture properties are set prior to being started. If you’re working with a Task, you can pass in the needed CultureInfo as the object state as shown in Listing 1 .

Now when you run the application, you’ll see that the new Threads and Task are using the set UI culture of the calling Thread, which is French, as shown in Figure 1.


[Click on image for larger view.]
Figure 1. The .NET Framework 4 Multi-Threaded Localization Demo

In .NET Framework 4.5, you have the ability to set a default culture for the UI and for any newly created threads. The CultureInfo.DefaultThreadCurrentCulture property is used to set the default culture for any newly created threads, and the CultureInfo.DefaultThreadCurrentUICulture property is used to set the default culture for the UI thread. By using the new properties, you can ensure that any newly created Thread or Task instances will use the set default CultureInfo within the executing AppDomain. Using this approach, the .NET Framework 4 samples above could be updated to no longer need the new CultureInfo setting for the created Thread or Task, as shown in Listing 2 .

The DefaultThreadCurrentCulture and DefaultThreadCurrentUICulture settings are applicable to the current AppDomain. If you create a new AppDomain, then you’ll need to set the DefaultThreadCurrentCulture and DefaultThreadCurrentUICulture for that AppDomain.

Let’s update the existing application to create a new AppDomain and display its set default UI culture. Open up the MainWindow.xaml file for the application, and add a label and TextBlock to display the new AppDomain’s set UI culture as follows:

<TextBlock>New AppDomain UI Culture</TextBlock>
<TextBlock Name="AppDomainUICulture" Text="{Binding DisplayName}"></TextBlock>

Your completed MainWindow.xaml markup file should now resemble the code in Listing 3 .

Now add a new method named AdditionalAppDomain to the MainWindow class of the application. The method will be responsible for creating a new AppDomain with custom default CultureInfo settings. To accomplish this task, first create an AppDomainSetup instance:

AppDomainSetup domainSetup = new AppDomainSetup();

Then call the AppDomainInitializer method on the AppDomainSetup instance passing in an Action<string[]> that sets the default thread culture and UI culture as follows:

domainSetup.AppDomainInitializer = (cultures) =>
 {
     CultureInfo.DefaultThreadCurrentCulture = CultureInfo.CreateSpecificCulture(cultures[0]);
     CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.CreateSpecificCulture(cultures[0]);
 };

Now set the initialization arguments for the AppDomainSetup for the needed culture you would call, for example, to set the default culture to Spanish.

domainSetup.AppDomainInitializerArguments = new string[] { "es-ES" };

Now you’re ready to create the actual new AppDomain through the AppDomain.CreateDomain static factory method as follows:

 AppDomain appDomain = AppDomain.CreateDomain("TestDomain", null, domainSetup);

When you call a method on the newly created AppDomain, the default culture will be set to the given culture name, in this case Spanish. Now add a new class called AppDomainCultureData that simply returns the current UI culture for its AppDomain.

public class AppDomainCultureData : MarshalByRefObject
 {
     public CultureInfo GetCultureInfo()
        {
            return CultureInfo.CurrentUICulture;
        } 
}

Next, create a new AppDomainCultureData instance via the new AppDomain, by using the CreateInstanceAndUnwrap method on the new AppDomain object.

AppDomainCultureData appDomainData = (AppDomainCultureData)appDomain.CreateInstanceAndUnwrap
(typeof(AppDomainCultureData).Assembly.FullName,
     typeof(AppDomainCultureData).FullName); 

Update the AppDomainUICulture TextBlock to display the DisplayName property on the new AppDomain’s current UI culture as follows:

Dispatcher.Invoke(() => AppDomainUICulture.DataContext = appDomainData.GetCultureInfo());

The last step is to call the AdditionalAppDomain function from the MainWindow constructor. Your completed MainWindow class should now look like the code shown in Listing 4 .

Now when you run the application, you’ll see the new AppDomain’s set UI culture as Spanish (Spain) as shown in Figure 2.


[Click on image for larger view.]
Figure 2. The .NET Framework 4.5 Multiple App Domains Localization Demo

As you can see, by utilizing the DefaultThreadCurrentCulture and DefaultThreadCurrentUICulture CultureInfo static properties, you can reduce the complexity of dealing with localized cultures in multi-threaded and multiple AppDomain applications.

About the Author

Eric Vogel is a Sr. Software Developer at Kunz, Leigh, & Associates in Okemos, MI. He is the president of the Greater Lansing User Group for .NET. Eric enjoys learning about software architecture and craftsmanship, and is always looking for ways to create more robust and testable applications. Contact him at vogelvision@gmail.com.

comments powered by Disqus

Reader Comments:

Add Your Comments Now:

Your Name:(optional)
Your Email:(optional)
Your Location:(optional)
Comment:
Please type the letters/numbers you see above

.NET Insight

Sign up for our newsletter.

I agree to this site's Privacy Policy.