Как я могу установить CultureInfo в WPF при запуске события? - PullRequest
1 голос
/ 09 января 2020

У меня есть приложение WPF для. NET 4.7.2 и я хочу установить глобальную культуру на основе аргументов командной строки. Согласно многим источникам (например, здесь или официальные документы ) культура в многопоточном приложении устанавливается с CultureInfo.DefaultThreadCurrentCulture . Это работает в конструкторе приложения. Однако он не работает там, где он мне нужен, а именно в событии Application_Startup, где я могу оценить аргументы командной строки. Почему это так и как я могу это исправить?

App.xaml:

<Application x:Class="WpfApp1.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:WpfApp1"
             StartupUri="MainWindow.xaml"
             Startup="Application_Startup">

    <Application.Resources>

    </Application.Resources>
</Application>

App.xaml.cs:

namespace WpfApp1
{
    public partial class App : Application
    {
        public App()
        {
            Demo("en-EN");
        }

        // Stops working if Demo is called in Application_Startup instead of constructor
        /* private void Application_Startup(object sender, StartupEventArgs e)
           {
               // TODO Take culture code from StartupEventArgs
               Demo("en-EN");
           }
        */

        private static void Demo(string cultureCode)
        {
            WriteDate();
            SetCulture(cultureCode);
            Task.Factory.StartNew(WriteDate);
        }

        private static void SetCulture(string code)
        {
            var ci = new CultureInfo(code);
            CultureInfo.DefaultThreadCurrentCulture = ci;
            CultureInfo.DefaultThreadCurrentUICulture = ci;
        }

        static void WriteDate()
        {
            var threadId = Thread.CurrentThread.ManagedThreadId;
            var threadCulture = Thread.CurrentThread.CurrentCulture;
            System.Diagnostics.Debug.WriteLine($"Thread {threadId} with culture {threadCulture} => {DateTime.Now}");
        }
    }
}

Моя системная культура немецкая. Вывод при использовании конструктора, как и ожидалось:

Thread 1 with culture de-DE => 09.01.2020 16:13:20
Thread 3 with culture en-EN => 1/9/2020 4:13:20 PM

Теперь, когда я перемещаю вызов Demo в событие Application_Startup, вывод:

Thread 1 with culture de-DE => 09.01.2020 16:16:10
Thread 3 with culture de-DE => 09.01.2020 16:16:10

Вызов к CultureInfo.DefaultThreadCurrentCulture не уважаемый! Интересно, что если я изменю этот вызов на Thread.CurrentThread.CurrentCulture, это решит проблему. Однако я хочу установить культуру для всех потоков, а не только для текущей.

Ответы [ 2 ]

1 голос
/ 10 января 2020

Вы можете определить пользовательскую точку входа и получить оттуда аргументы:

public class Program
{
    static void Main(string[] args)
    {
        App app = new App(args);
        app.InitializeComponent();
        app.Run();
    }
}

public partial class App : Application
{
    public App(string[] args)
    {
        Demo("en-EN");
    }

    private static void Demo(string cultureCode)
    {
        WriteDate();
        SetCulture(cultureCode);
        for (int i = 0; i < 100; i++)
            Task.Run((Action)WriteDate);
    }

    private static void SetCulture(string code)
    {
        var ci = new CultureInfo(code);
        CultureInfo.DefaultThreadCurrentCulture = ci;
    }

    static void WriteDate()
    {
        var threadId = Thread.CurrentThread.ManagedThreadId;
        var threadCulture = Thread.CurrentThread.CurrentCulture;
        System.Diagnostics.Debug.WriteLine($"Thread {threadId} with culture {threadCulture} => {DateTime.Now}");
    }
}

Не забудьте изменить Build Action из App.xaml на Page, чтобы компилятор не генерировал Main метод для вас.

0 голосов
/ 09 января 2020

Трудно ответить, в чем причина, но, глядя на потоки windows Я полагаю, что фоновые задачи для обработки пула потоков создаются до того, как будет запущено событие Application_Startup. Вы можете видеть 1 поток в конструкторе приложения и 3 потока в событии запуска. Скорее всего, один из них используется для обработки задач.

Я вижу 2 возможных решения:

1) В конструкторе приложений вы также можете получить доступ к аргументам командной строки, используя Environment, поэтому просто сохраняйте logi c в конструкторе:

Environment.GetCommandLineArgs()

2) Установить его для всех потоков - перечислить их в Application_Startup и установить культуру для всех , используя этот ответ stackoverflow

...