So what happened in v.Next?

by Michael S. Kaplan, published on 2005/04/05 02:02 -04:00, original URI: http://blogs.msdn.com/b/michkap/archive/2005/04/05/405443.aspx


A few days ago I talked about how ClearCachedData found its way into the .NET Framework. I told the whole fun story, and I waited hopefully for someone to ask the question.

I explained how it was too late to do anything more extensive in the first version of the .NET Framework. And held my breath waiting for the question.

Alas, the question did not come.

What was the question, you may ask?

The question was "so what happened in version 1.1?" I mean, we cannot refuse to address issues in a later release that are "too late to address" in the current relese, can we?

I assume everyone was just so beguiled by the excellent storytelling job I did that no one noticed.

Well, technically one person asked the question, but I believe he is the one who was behind it so I couldn't count him. :-)

Version 1.1 of the .NET Framework (Everett) added the SystemEvents.UserPreferenceChanged event!

By using the UserPrefereceChangedEventArgs.Category of UserPreferenceCategory.Locale, you will be getting the same notification that the WM_SETTINGCHANGE message with a wParam of 0 and an lParam of "intl". The very message that means someone has changed a setting in Regional Options!

Unfortunately it cannot tell you what has changed, but then again the WM_SETTINGCHANGE cannot tell you either. But it can tell you that something has changed. So if you are caching anything, you have to dump your cache. But that is just what CultureInfo.ClearCachedData is meant to do, so everything works out quite nicely. Like a marriage made in Arkon, as my 7th grade teacher would have said....

Now there is no specific sample for using this event for locales, but I figured no body would mind if I whipped one up here for this post.

First create the event procedure in your main class:

public void UserPreferenceChanged(object sender,
  Microsoft.Win32.UserPreferenceChangedEventArgs e) {

    switch(e.Category)
    {
        case UserPreferenceCategory.Locale:
            Thread.CurrentThread.CurrentCulture.ClearCachedData();
            break;

        default:
            break;

    }

}

Then to make sure it gets called by adding the following in your constructor:

Microsoft.Win32.SystemEvents.UserPreferenceChanged 
  += new Microsoft.Win32.UserPreferenceChangedEventHandler(
     this.UserPreferenceChanged);

Finally, make sure to add the following to the form's Dispose event to unhook the event:

Microsoft.Win32.SystemEvents.UserPreferenceChanged 
  -= new Microsoft.Win32.UserPreferenceChangedEventHandler(
     this.UserPreferenceChanged);

And that is all you have to do; let the .NET Framework do the rest....

One final thought -- don't look longingly at the SystemEvents.UserPreferenceChanging event, it does not really add anything here. :-)

 

This post brought to you by "Ļ" (U+013b, a.k.a. LATIN CAPITAL LETTER L WITH CEDILLA)
A letter that for some unknown reason was quite excited about the notion of hooking the "Locale changing" event!


# Eric on 5 Apr 2005 9:18 AM:

Will UserPreferenceChanged always be raised on the UI thread, or should one call Form.Invoke in order to make sure the "right" thread's CurrentCulture is affected?

# Michael S. Kaplan on 5 Apr 2005 10:29 AM:

The message technically goes to the top level windows and also to threads (I think the latter is used), and you can always have more than one of those.

But technically you should be able to call it from anywhere and see it reset the data all over (the cache is not itself per thread). The truly paranoid could enumerate threads and call it repeatedly from all of them, but I believe the results would be the same.

And of course you could do the more complicated dance that I referred to in the code in the article (http://msdn.microsoft.com/msdnmag/issues/05/03/CultureInfo/) but the purpose here was just to show the event, not the plumbing....

# Eric on 5 Apr 2005 11:43 AM:

Incidentally, the code in that article doesn't compile. The else is missing a closing bracket, and localeCur is a variable, not a method, but it has parens after it. :)

# Michael S. Kaplan on 5 Apr 2005 12:29 PM:

Oops! Sorry about that. :-(

# Ruben on 5 Apr 2005 4:11 PM:

I meant to ask that. Honest! But a comment on the docs though: jeez, could they be any more contradictory?

"The ClearCachedData method refreshes the information in CurrentCulture, ..."

right next to

"This method does not refresh the information in CurrentCulture for existing threads."

Isn't the current thread an "existing thread"?

What about changing your regional settings to a completely different culture, not just changing some values. I guess this is covered here as well? All new LCID and Name properties and such? In that case: what does ClearCachedData do on a culture not bound to Current(UI)Culture (CreateSpecificCulture, new()). It doesn't say! (Hint: a small yes and a big NO!)

Thankfully, Reflector tells me that the static properties Current(UI)Culture of CultureInfo (and some more) are reset, not the properties of the culture you used to call ClearCachedData on. Somehow I get the feeling that this method should have been static...

Oh, and didn't your mother tell you never to lock(typeof(...))? ;-)

# Michael S. Kaplan on 6 Apr 2005 9:18 AM:

The docs are a little confusing on this point -- they mean to refer to the fact that the ones in other threads have this issue. If you need to, you can actually either put the listener in other threads or just enumerate the threads and call it on each one.

Which I guess explains why it is an instance method, because although its biggest effect is static there are some instnace features, too....

The current behavior of a culture that is not the user default (and has not been the user default since creation or the last time ClearCachedData was called) is that it just makes the data get re-fetched. But if that ever changed this would be the method to get those changes made, right? :-)

Pesky Reflector!!! :-)

# Scott on 20 Apr 2005 10:54 AM:

About the threading of UserPreferenceChanged, if you're using Windows Forms controls (or anything with thread affinity), you should invoke.

referenced by

2011/01/03 Bad news: you may have to clear the cache; Good news: you *can* clear the cache

go to newer or older post, or back to index or month or day