четверг, 25 декабря 2014 г.

WPF set application-wide Culture, NumberFormat, Decimal separator

WPF by default uses built-in culture settings that come with .Net Framework libraries.

For example, for ru-RU culture double must look like 123456,789, for en-US like 123456.789, so if you don't want your users to be angry, you must set your application culture at startup. However, our users want to see doubles like in en-US culture, e.g. 123456.789

There are two ways to do this:

1. Modify current culture settings. And that is awful
   a. Not all controls support such behaviour
   b. This code breaks all your hopes:
    XmlLanguage xmlLanguage = XmlLanguage.GetLanguage("ru-RU");
    FrameworkElement.LanguageProperty.OverrideMetadata(typeof (FrameworkElement),
                                                       new FrameworkPropertyMetadata(xmlLanguage)); 

    XmlLanguage ignore all modifications to Thread.CurrentThread.CurrentCulture

2. Register your own culture (works if your users can get administator rights).


        private const string CultureName = "ru-MIT";
        private const string cultureEnglishName = "ru-MIT";
        private const string cultureNativeName = "Русский (Мит)";

        private static void Main(string[] args)
        {
            CreateAndRegisterOwnCulture();
        }

        private static void CreateAndRegisterOwnCulture()
        {
            var ownCulture = new CultureAndRegionInfoBuilder(CultureName, CultureAndRegionModifiers.None);

            var parentCulture = new CultureInfo("ru-RU");
            var region = new RegionInfo("RU");
            ownCulture.LoadDataFromCultureInfo(parentCulture);
            ownCulture.LoadDataFromRegionInfo(region);

            ownCulture.CultureEnglishName = cultureEnglishName;
            ownCulture.CultureNativeName = cultureNativeName;

            var nfi = (NumberFormatInfo) parentCulture.NumberFormat.Clone();
            nfi.NumberDecimalSeparator = ".";
            nfi.NumberGroupSeparator = " ";
            nfi.CurrencyDecimalSeparator = ".";
            nfi.CurrencyGroupSeparator = " ";

            ownCulture.NumberFormat = nfi;
            ownCulture.Parent = parentCulture;


            if (SystemHasMitCulture())
            {
                Console.WriteLine(">>> System already has own culture :)");
                return;
            }

            // Admin rights are needed here
            // CultureAndRegionInfoBuilder.Unregister(CultureName);

            try
            {
                // Admin rights are needed here
                Console.WriteLine(">>> Trying to set own culture");
                ownCulture.Register();
                Console.WriteLine(">>> Own culture set successfully");
            }
            catch (UnauthorizedAccessException)
            {
                Console.WriteLine(">>> Set own culture failed :(");
            }
            catch (InvalidOperationException)
            {
                Console.WriteLine(">>> Culture is already registered :)");
            }
        }

        private static bool SystemHasMitCulture()
        {
            return CultureInfo.GetCultures(CultureTypes.UserCustomCulture).Any(ci => (ci.Name == CultureName));
        }

The same code on Github Gist: https://gist.github.com/Snegovikufa/f051959dd105b7e56405

Configuring Jenkins for C# projects

Steps in my build configuration Restore nuget packages chcp 1251 .nuget\nuget.exe restore Swag.sln Build solution chcp 1251 cmd.e...