Title: In .Net: best way for keeping CurrentCulture on new Thread?
Tags: .net;wpf;multithreading;c#-4.0;culture
Question: In a .Net 4.0 WPF project, we need to keep the same CurrentCulture on each thread then we have on the main thread.
Given, we can initialize a new thread's culture with code like the following:
Keep the information in a variable (context)
context.CurrentCulture = Thread.CurrentThread.CurrentCulture;
context.CurrentUICulture = Thread.CurrentThread.CurrentUICulture;
On the new thread, initialize from the saved context
Thread.CurrentThread.CurrentCulture = context.CurrentCulture;
Thread.CurrentThread.CurrentUICulture = context.CurrentUICulture;
But in this age of TPL, async programming and lambda delegates, it does not feel right.
And yes, we actually can change the culture while the application is running, but that is another story.
Do you know of any setting, property or config we should initialize to keep track?


Here is another answer: When i Create Tasks with the TPL i always Pass the Culture fomr the Current UI-Thread. See sample Code below.
private void WorkProcessingAsync(IWorkItem workItem)
{
IsBusy = true;
/* =============================
*  Create a TPL Task and pass the current UiCulture in an state Object to resolve the correct .resx file for translation / globalisation / Multilanguate features in Background Thread
* ==============================*/
Task<IWorkItem&gt; task = Task.Factory.StartNew((stateObj) =&gt;
{
// here we are already in the task background thread
// save cast the given stateObj
var tuple = stateObj as Tuple<IWorkItem, CultureInfo&gt;;
Debug.Assert(tuple != null, "tuple != null");
Thread.CurrentThread.CurrentUICulture = tuple.Item2;   // Here we set the UI-Thread Culture to the Background Thread
var longRunningOperationAnswer = LongRunningOperation.DoLongWork(tuple.Item1);
return longRunningOperationAnswer;
}, new Tuple<IWorkItem, CultureInfo&gt;(workItem, Thread.CurrentThread.CurrentUICulture));  // here we pass the UI-Thread Culture to the State Object
/* =======================================================================
*   Handle OnlyOnRanToCompletion Task and process longRunningOperationAnswer back in UiThread
* =======================================================================*/
task.ContinueWith((t) =&gt;
{
IsBusy = false;
// handle longRunningOperationAnswer here in t.Result
Log.Debug("Operation completet with {0}", t.Result);
}, CancellationToken.None
, TaskContinuationOptions.OnlyOnRanToCompletion
, TaskScheduler.FromCurrentSynchronizationContext());
/* =======================================================================
*   Handle OnlyOnFaulted Task back in UiThread
* =======================================================================*/
task.ContinueWith((t) =&gt;
{
IsBusy = false;
AggregateException aggEx = t.Exception;
if (aggEx != null)
{
aggEx.Flatten();
Log.ErrorFormat("The Task exited with Exception(s) \n{0}", aggEx);
foreach (Exception ex in aggEx.InnerExceptions)
{
if (ex is SpecialExaption)
{
//Handle Ex here
return;
}
if (ex is CustomExeption)
{
//Handle Ex here
return;
}
}
}
}, CancellationToken.None
, TaskContinuationOptions.OnlyOnFaulted
, TaskScheduler.FromCurrentSynchronizationContext());
}
I needed to pass the uiculture to resolve the correct translation.resx for translation

Here is another answer: There is no good way, avoid this at all cost.  The fundamental problem is that culture is not part of the Thread.ExecutionContext, it doesn't flow from one thread to another.  This is a unsolvable problem, culture is a property of a native Windows thread.  It will always be initialized to the system culture as selected in Control Panel's Region and Language applet.
Making temporary thread-local changes to the culture is fine, trying to switch 'the process' to another culture is a source of bugs you'll be hunting for months.  The string collation order is the nastiest source of problems.
EDIT: this problem was fixed in .NET 4.5 with the CultureInfo.DefaultThreadCurrentCulture and DefaultThreadCurrentUICulture properties.
EDIT: and got the real solution in .NET 4.6, culture now flows from one thread to another.  Check the MSDN article for CultureInfo.CurrentCulture for details.  Beware that the description does not quite match behavior, testing required.
Comment for this answer: And further fixed in .NET 4.6, where it became part of the ExecutionContext.

Here is another answer: I don't understand why Mr. Passant warns about this and simultaneously says it's fine making "temporary" "thread-local" changes to the culture. No thread culture is truly thread-local - it's available to anything that can reference the thread via public properties, as we've seen. And if it's OK to change it for a short time, then why isn't it ok to change it for a longer time? Where do you cross the line, and why?
Nor do I really understand the OP's feeling that it "shouldn't be necessary" to write code to copy the stuff he wants to copy. You may want to put this code somewhere where you can reuse it, but apart from that I really don't see the problem with the code. In my book, it's rather more straightforward and wonderful than any lambda expression I've ever seen, and it would do the job quite nicely. Writing fancy code for the sake of it being fancy is not my style, at least.
You could do something like this:
// Program.cs
static CultureInfo culture, uiCulture;
[STAThread]
static public void Main()
var t = Thread.CurrentThread;
culture = t.CurrentCulture;
uiCulture = t.CurrentUICulture;
static public Thread CreateThread()
return new Thread() { CurrentCulture = culture, CurrentUICulture = uiCulture }; }
Comment for this answer: @CodeInChaos inside the delegate for `ThreadPool.QueueUserWorkItem(...)` you can use the static `Thread.CurrentThread.CurrentCulture = myCulture` then. You can also encapsulate all that in a helper method.
Comment for this answer: And with threads created outside of your control such as threadpool threads CurrentCulture gets even uglier.

Here is another answer: By the way, it just dawns upon me that although the default culture comes from Windows' "Regional Settings", it can probably be overridden in the .NET configuration.
If this was an ASP.NET app you'd use the globalization element in web.config. I'd probably start out somewhere like here to learn about localization in WPF:
http://msdn.microsoft.com/en-us/library/ms788718.aspx#workflow_to_localize
(Is it me, or does Microsoft use the words globalization and localization, rather confusingly, interchangeably?)
Comment for this answer: Actually the answer to your last question is no, *globalization* is the process of preparing your application for subsequent *localization*. I.e. an application may be fully globalized and have no localizations available besides the default one.

{'source': 'StackExchangeDataset', 'subset': 'stackoverflow.com', 'metadata': {'AnswerCount': 4, 'CommentCount': 0, 'ContentLicense': 'CC BY-SA 3.0', 'CreationDate': '2011:00:02/28/11', 'FavoriteCount': 3.0, 'PostTypeId': 1, 'Tags': '<.net><wpf><multithreading><c#-4.0><culture>', 'Title': 'In .Net: best way for keeping CurrentCulture on new Thread?', 'ViewCount': 6493, 'id': 5144314, 'user_AboutMe': '', 'user_AccountId': 32960.0, 'user_DisplayName': 'PBelanger', 'user_Reputation': 1279.0, 'user_Views': 110.0, 'user_id': 91825.0}}