Skip to main content

Testing when the culture changes in WPF

Recently I've do some work on a WPF app which required to support multiple languages in the UI - a spike to see how easy supporting multiple languages is in WPF, the test UI is shown below in English & French:
The app is easy enough to understand - change the UI language and all the text based values are updated with the locale specific instances. I wanted to follow the standard pattern of using language specific resource files to store the translated text, these were placed in the standard location inside the project structure:
One of the big advantages of using this mechanism is the resources are compiled into a class which can be used in your ViewModels and Views and this is why see above the 'Resource.resx' file - this contains the 'untranslated' resource strings etc:
I've been aware for a long time there are 2 culturing settings per thread in .Net - Thread.CurrentCulture & Thread.CurrentUICulture, the second is the one of interest here, it is used by the ResourceManager to load the correct resources at run-time. What's interesting  is in .Net 4.5 they introduced a couple of static methods to set these properties globally - CultureInfo.DefaultThreadCurrentCulture & CultureInfo.DefaultThreadCurrentUICulture, once set these are used as the default setting for all threads created after this point. This brings up an interesting scenario - if you create a thread before initializing these properties it will default to the behavior seen in .Net 4.0, it will take the current culture from the system locale (windows system culture), but once set then any existing threads will be updated (in the same app-domain). The default value for both properties is NULL, I was expecting it to be set to the system locale.

To keep my ViewModels simple, I decided to push the complexity of using these new properties into a service which is able to notify any interested ViewModels when the selected culture has changed:
Loading ....

As you can see I'm using the CultureChanged property to notify anyone interested when the thread UI culture has changed. To make sure the same instance is shared between all ViewModel instances, the interface & class are registered as a singleton with the IoC container (Autofac):
This then allows a ViewModel to update any text which needs to be translated when the current culture changes, the following snippet shows the CultureChanged property being subscribed too and when the stream pumps it raises IPNC for all the required fields on the ViewModel:
So the point of the post was testing when the culture changes and this is done by putting the implementation of the ICultureService interface under test, this was easy as the service has a high level of SRP, infact I only need 3 tests to cover off the behaviour. The first two are straight forward they test when the culture changes we get notified via the CultureChanged property:
As you can see from the green icons these tests are passing as expected - the icons are a visualisation provided by nCrunch.

The third test produced the interesting results, this test was not specifically testing the CultureService, it was more around testing the vertical slice of changing culture - when the culture changes then the ResourceManager should provide the correctly translated text when requested.

To test this requires translated resource strings in culture specific *.resx files, the following screenshot shows resources for English & French and the test:
Does the test pass or fail?

It depends...

When run as a single test from either nCrunch, Resharper or any other test runner it works as expected:
But when run as part of a group of tests - running all tests in a class or assembly then it will fail:
How can this be explained?

I thought it must be because the ResourceManager only gets updated on the dispatcher thread - I was thinking single tests are run on the UI (dispatcher) thread, where as if your running multiple tests they are run on a background thread. A quick look at the threads running threads showed this wasn't the case, single test:
Multiple tests running (also on a work thread):
At this point I gave up looking for a reason for the failure and started looking for a workaround solution to getting it working when running multiple tests, the answer turned out to be simple - explicitly set the compiled Resource class Culture property, this is done in a CultureChanged property subscription:
The updated test now looks like this:

Comments

Popular posts from this blog

Integrating jasmine into Visual Studio 2010/2011 beta

Following on from my previous post about testing javascript with jasmine. I was interested to explore integration into visual studio 2010 so I could run them along side test written in another language like C#. I found the VS 2010 extension Chutpah (pronounced  'hutz-pah'). This got me up and running with the ability to run test manually and to my surprised it worked by only have the SpecRunner.html file open. I didn't a csproj or sln file containing the javascript, it's clever enough to resolve all dependencies: Test results are render in the output window of VS 2010: This is good and I appreciate the work someone has done to get this far but I want more... I want integration into Resharper... A quick squizz on the inter'webs and I end posting a request on jetBrains forum , it looks like support is coming in R# 7. Then I thought lets check out the current beta and see, so off I go and boot Win8 and install R#7 beta and see if it's there yet... ...

Showing a message box from a ViewModel in MVVM

I was doing a code review with a client last week for a WPF app using MVVM and they asked ' How can I show a message from the ViewModel? '. What follows is how I would (and have) solved the problem in the past. When I hear the words ' show a message... ' I instantly think you mean show a transient modal message box that requires the user input before continuing ' with something else ' - once the user has interacted with the message box it will disappear. The following solution only applies to this scenario. The first solution is the easiest but is very wrong from a separation perspective. It violates the ideas behind the Model-View-Controller pattern because it places View concerns inside the ViewModel - the ViewModel now knows about the type of the View and specifically it knows how to show a message box window: The second approach addresses this concern by introducing the idea of messaging\events between the ViewModel and the View. In the example ...

WPF tips & tricks: Dispatcher thread performance

Not blogged for an age, and I received an email last week which provoked me back to life. It was a job spec for a WPF contract where they want help sorting out the performance of their app especially around grids and tabular data. I thought I'd shared some tips & tricks I've picked up along the way, these aren't probably going to solve any issues you might be having directly, but they might point you in the right direction when trying to find and resolve performance issues with a WPF app. First off, performance is something you shouldn't try and improve without evidence, and this means having evidence proving you've improved the performance - before & after metrics for example. Without this you're basically pissing into the wind, which can be fun from a developer point of view but bad for a project :) So, what do I mean by ' Dispatcher thread performance '? The 'dispatcher thread' or the 'UI thread' is probably the most ...