Обновлять принудительный пользовательский интерфейс "на лету" после изменения текущей культуры в WPF

Мне нужно поддерживать изменение языка пользовательского интерфейса в меню приложения. Тексты локализуются с использованием файлов ресурсов (аналогично подходу 1 здесь)

если я устанавливаю Thread.CurrentThread.CurrentUICulture до того, как ctor вызывает InitializeComponent(), пользовательский интерфейс изменяется как следует.

Однако, если параметр CurrentUICulture изменяется во время обычного запуска приложения, элементы управления не обновляются (т.е. текст остается неизменным, независимо от текущей культуры).

Есть ли способ заставить элементы управления обновляться в соответствии с CurrentUICulture?

Ответы

Ответ 1

Вы можете использовать подход ResourceDictionary вместе с DynamicResourceMarkupExtension. Используя этот подход, вы можете поменять словарь ресурсов, представляющий язык, выбранный пользователем, и DynamicResourceMarkupExtension обеспечит отражение нового значения в пользовательском интерфейсе.

Кроме того, если вы готовы рисковать в область пользовательского решения, есть LocalizeMarkupExtension, который предоставляется в этот учебник WPF.

Ответ 2

Предполагая, что DataContext для меню является объектом, который реализует INotifyPropertyChanged, вы можете обновить все элементы управления, указав null (ничего) в событии PropertyChanged...

from msdn:

Событие PropertyChanged может указывать все свойства объекта изменено с помощью либо нулевого ссылка (ничего в Visual Basic) или String.Empty как имя свойства в PropertyChangedEventArgs.

Ответ 3

Способ, которым я старался и работает хорошо, - этот метод, чтобы вызвать после назначения свойства в ViewModel:

private void AllowUiToUpdate()
{
    var frame = new DispatcherFrame();

    var dispatcherOperationCallback = new DispatcherOperationCallback(delegate
        {
            frame.Continue = false;
            return null;
        });

    Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Render, dispatcherOperationCallback, null);

    Dispatcher.PushFrame(frame);
}