CurrentUICulture ignores Region and Language settings

风流意气都作罢 提交于 2019-12-01 05:09:52
Sphinxxx

This SO post (WPF/Silverlight) has a link to this article (WPF only), explaining how to use CurrentCulture as the default for your application. Does that solve your problem?

EDIT:

Making bindings use the custom settings from "Region and Language" instead of the current language's default settings requires some more trickery. This post concludes that every binding's ConverterCulture also has to be explicitly set to CultureInfo.CurrentCulture. Here are some DateTime tests:

<!-- Culture-aware(?) bindings -->
<StackPanel DataContext="{Binding Source={x:Static sys:DateTime.Now}}" >

    <!-- WPF's default en-US formatting (regardless of any culture/language settings) -->
    <TextBlock Text="{Binding Path=.}" />

    <!-- *Default* norwegian settings (dd.MM.YYY) -->
    <TextBlock Text="{Binding Path=., ConverterCulture=nb-NO}" />

    <!-- Norwegian settings from the "Region and Languague" dialog (d.M.YY) -->
    <TextBlock Text="{Binding Path=., ConverterCulture={x:Static sysglb:CultureInfo.CurrentCulture}}" />

    <!-- Hiding ConverterCulture initialization in our own custom Binding class as suggested here:
         https://stackoverflow.com/questions/5831455/use-real-cultureinfo-currentculture-in-wpf-binding-not-cultureinfo-from-ietfl#5937477 -->
    <TextBlock Text="{local:CultureAwareBinding Path=.}" />

</StackPanel>

The custom binding class:

public class CultureAwareBinding : Binding
{
    public CultureAwareBinding()
    {
        this.ConverterCulture = System.Globalization.CultureInfo.CurrentCulture;
    }
}

It all ends up looking like this on a norwegian machine:

There is one very dirty way to do it in WPF, but as far as I could find it is the best, because it works without any other extra code or having specific culture aware bindings. The only thing you have to do is call SetFrameworkElementLanguageDirty method (below in the answer) in your application startup or even better in constructor of the App.

The method comments are self-explanatory, but in short the method overrides the default metadata of LanguageProperty of FrameworkElement with CurrentCulture including user's specific modification from windows, if there are any. The downsize/dirty part is that it is using reflection to set a private field of XmlLanguage object.

    /// <summary>
    ///   Sets the default language for all FrameworkElements in the application to the user's system's culture (rather than
    ///   the default "en-US").
    ///   The WPF binding will use that default language when converting types to their string representations (DateTime,
    ///   decimal...).
    /// </summary>        
    public static void SetFrameworkElementLanguageDirty()
    {
        // Note that the language you get from "XmlLanguage.GetLanguage(currentCulture.IetfLanguageTag)"
        // doesn't include specific user customizations, for example of date and time formats (Windows date and time settings).            
        var xmlLanguage = XmlLanguage.GetLanguage(Thread.CurrentThread.CurrentCulture.IetfLanguageTag);
        SetPrivateField(xmlLanguage, "_equivalentCulture", Thread.CurrentThread.CurrentCulture);

        FrameworkElement.LanguageProperty.OverrideMetadata(typeof(FrameworkElement), new FrameworkPropertyMetadata(xmlLanguage));
    }

The SetPrivateField method can look like this.

    private static void SetPrivateField(object obj, string name, object value)
    {
        var privateField = obj.GetType().GetField(name, BindingFlags.Instance | BindingFlags.NonPublic);
        if (privateField == null) throw new ArgumentException($"{obj.GetType()} doesn't have a private field called '{name}'.");

        privateField.SetValue(obj, value);
    }
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!