How to use Windows' Customized Region and Language settings in WPF
Asked Answered
N

2

7

I am working in Namibia. Namibia is not an option on the Windows Region and Language settings, but share most cultural specifics with South Africa, so we select English South Africa and then customize the currency symbol to be "N$" (Namibian Dollars) and not "R" (South African Rand).

However, I can't convince WPF to use the customized currency. Using string.format("{0:c}", foo) in code works fine, but using {Binding Path=SomeCurrencyValue, StringFormat=c}` in XAML still uses the "R" symbol and not the custom "N$" symbol.

In App.xaml.cs I set the Application Culture with the following code:

System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo(System.Globalization.CultureInfo.CurrentCulture.LCID, true);

FrameworkElement.LanguageProperty.OverrideMetadata(typeof(FrameworkElement),
                                                        new FrameworkPropertyMetadata(
                                                            System.Windows.Markup.XmlLanguage.GetLanguage(
                                                                System.Globalization.CultureInfo.CurrentUICulture.IetfLanguageTag)));

As demonstration, here is some XAML code that shows the problem:

<StackPanel>
    <TextBlock>
        Formatted in XAML with: <LineBreak/>
        Text="{Binding Path=SomeCurrencyValue, StringFormat=c}" <LineBreak/>
        Result:
    </TextBlock>

    <TextBox Text="{Binding Path=SomeCurrencyValue, StringFormat=c, Mode=OneWay}"
             Margin="5"/>

    <TextBlock>
        Formatted in code with: <LineBreak/>
        return string.Format("{0:c}", SomeCurrencyValue); <LineBreak/>
        Result:
    </TextBlock>

    <TextBox Text="{Binding Path=SomeCurrencyString, Mode=OneWay}"
             Margin="5"/>

</StackPanel>

The DataContext for the above View contains the following:

public double SomeCurrencyValue
{
    get { return 34.95; }

}

public string SomeCurrencyString
{
    get
    {
        return string.Format("{0:c}", SomeCurrencyValue);
    }
}

And the result looks like this: Currency Issue Result

I know there is a similiar question here, but I was hoping to get better answers with a more complete question. I am mostly working on financial applications for Namibian clients, so this is quite a serious issue for me - if there is no way to do this with .NET 4.0, I would consider filing a bug report, but I just wanted to check here first.

EDIT:

Just opened up the bounty on this question. I'm hoping for either a solution that isn't a rediculous workaround, or confirmation that this is a bug and should be filed as such.

Nunley answered 8/9, 2011 at 7:56 Comment(7)
Did you try using converters? Is that an option for you?Forefather
My problem with using converters is mostly that I then have to do the conversion manually - with the stringformat in the binding, the binding takes cares of user input like "N$50" or "N$ 5 000 000.00". Doing it manually won't be trivial, unless I can somehow extend the default converter but I don't know if that will be possible.Butterfly
I was just about to post an answer that you can use the Language property for any FrameworkElement but I couldn't get it to work with Namibian Dollars. The closest I got was <TextBox Language="en-NA" .../> but that's Namibia English.. Also, I noticed no difference between the currency presentation from Xaml or codePrinciple
A cool workaround would be some (sane) way of getting the custom currency symbol from the operating system, but I have no idea how to go about that.Butterfly
The problem for me is that I can't find the culture code for Namibia, what is it? Actually, I went through all the cultures in my Windows 7 system and printed the currency symbol but N$ didn't show up. In a new project, without setting the culture, what is your values for CultureInfo.CurrentCulture.IetfLanguageTag and CultureInfo.CurrentCulture.NumberFormat.CurrencySymbol?Principle
Read the question again - There IS no Namibian culture - that is the source of the problem. In Namibia we set our Windows cultures to South Africa, then CUSTOMIZE the currency symbol to Namibian Dollar (N$). The Custom currency symbol is where the problem starts.Butterfly
@Harikawashi: Sorry, I missunderstood the question. Don't know how since when I read it now, it's crystal clear. Anyway, that explains why I wasn't able to find it :)Principle
H
4

One solution to this is to create this Namibian CultureInfo, so its fully recognized by all .NET layers. Here is a code that does it:

public static void RegisterNamibianCulture()
{
    // reference the sysglobl.dll assembly for this
    CultureAndRegionInfoBuilder namibianCulture = new CultureAndRegionInfoBuilder("en-NA", CultureAndRegionModifiers.None);

    // inherit from an existing culture
    namibianCulture.LoadDataFromCultureInfo(new CultureInfo("en-za"));
    namibianCulture.CultureEnglishName = "Namibia";
    namibianCulture.RegionEnglishName = "Namibia";
    namibianCulture.CultureNativeName = "Namibia"; // you may want to change this
    namibianCulture.RegionNativeName = "Namibia"; // you may want to change this

    // see http://en.wikipedia.org/wiki/ISO_3166-1, use user-defined codes
    namibianCulture.ThreeLetterISORegionName = "xna"; // I use x as 'extended' and 'na' as namibia
    namibianCulture.TwoLetterISORegionName = "xn";
    namibianCulture.ThreeLetterWindowsRegionName = namibianCulture.ThreeLetterISORegionName;

    // see http://www.currency-iso.org/dl_iso_table_a1.xml
    namibianCulture.ISOCurrencySymbol = "nad";
    namibianCulture.CurrencyEnglishName = "Namibia Dollar";
    namibianCulture.CurrencyNativeName = "Namibia Dollar"; // you may want to change this

    // this is were you build something specific, like this symbol you need
    namibianCulture.NumberFormat.CurrencySymbol = "N$";

    // you'll need admin rights for this
    namibianCulture.Register();
}

public static void UnregisterNamibianCulture()
{
    CultureAndRegionInfoBuilder.Unregister("en-NA");
}

Once you have called the Register function once on a given machine (you will need to install this culture on end user machines), you can now use your initial WPF startup code, just change it like this:

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

And everything should work as expected. You can also use standard language tags and all that jazz, since en-NA is now recognized.

Horseplay answered 19/9, 2011 at 17:4 Comment(2)
This looks VERY promising. I'll make an effort to test it tomorrow so I can mark the answer. ThanksButterfly
Hi Simon - I have concidered your answer, and although I think you deserve the bounty, I don't want to mark it as answered - I think the real question is still unanswered: "How can I access the Customized currency on the Windows Culture". Because, although your answer will solve my problem, it doesn't generalize - what if the user is NOT Namibian, or wants to use his own custom settings? Windows provides an interface for customizing the currency symbol - WPF SHOULD provide an interface for accessing that setting. Thanks again, although I've not marked it as answer, I have upvoted your answer.Butterfly
C
1

I had the same problem and I started from Simon's answer (thank you, Simon) making some modifications in order to get the user configuration (Region and Language in Control Panel) every time the application is launched, not the culture default.

My code look like this one

public MainWindow()
{
    CreateAndRegisterLocalizedCulture();
    this.Language = XmlLanguage.GetLanguage(customCultureName);

    InitializeComponent();

    DataContext = new ViewModel();
}

private void CreateAndRegisterLocalizedCulture()
{
    CultureAndRegionInfoBuilder customCulture = new CultureAndRegionInfoBuilder(customCultureName, CultureAndRegionModifiers.None);

    // Inherits from the current culture and region, may be configured by the user
    customCulture.LoadDataFromCultureInfo(CultureInfo.CurrentCulture);
    customCulture.LoadDataFromRegionInfo(RegionInfo.CurrentRegion);

    // Not needed for the culture sake but... 
    customCulture.CultureEnglishName = CultureInfo.CurrentCulture.EnglishName + "-Customized";
    customCulture.CultureNativeName = CultureInfo.CurrentCulture.NativeName + "-Customized";

    // If the custom culture is already registered an unregistration is needed
    // otherwise the following Register() call will generate an exception
    if (CultureInfo.GetCultures(CultureTypes.UserCustomCulture).Where(ci => (ci.Name == customCulture)).Count() != 0)
    {
        // Admin rights are needed here
        CultureAndRegionInfoBuilder.Unregister(customCulture);
    }

    // Admin rights are needed here
    customCulture.Register();
}

It works fine to me but there are two problems in this approach:

  1. In windows 7+ you need to start the application with Administrator rights as it will create a new culture file in C:\Windows\Globalization with the name you give to your custom culture
  2. The Unregister method does not delete the above create file but it renames it as xyz.tmp0 and, with a logic I didn't get, time to time it creates more tmp file copies (xyz.tmp1, xyz.tmp2, ...). At least it is how it works in my pc.

Something that is not really a problem but a bit weird is that, once I change my regional settings in the control panel, I have to start my application twice before I see the modification. I can survive :)

Cursorial answered 9/1, 2013 at 16:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.