CurrentUICulture ignores Region and Language settings

前端 未结 2 965
陌清茗
陌清茗 2021-01-12 16:55

Assorted settings in the Windows 7 Region and Language dialog supply values to the properties of the CurrentCulture object. However, WPF controls seem to use CurrentUICultur

2条回答
  •  小鲜肉
    小鲜肉 (楼主)
    2021-01-12 17:30

    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.

        /// 
        ///   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...).
        ///         
        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);
        }
    

提交回复
热议问题