WPF在运行时更改整个应用程序区域性



我有一个大型的WPF应用程序,要求在运行时有一个切换语言/区域性的菜单。它用于文本本地化,但也用于单元(例如:使用Culture的RegionInfoIsMetric属性的KMH/MPH(,甚至生成一些URL,例如用正确的语言打开用户手册pdf。

在.NET 4.7.2中,我有一个运行良好的解决方案:

var language = XmlLanguage.GetLanguage(culture.Name);
foreach (Window childWindow in Application.Current.Windows)
{
childWindow.Dispatcher.Thread.CurrentCulture = culture;
childWindow.Dispatcher.Thread.CurrentUICulture = culture;
childWindow.Language = language;
}
Thread.CurrentThread.CurrentCulture = culture;
Thread.CurrentThread.CurrentUICulture = culture;
CultureInfo.DefaultThreadCurrentCulture = culture;
CultureInfo.DefaultThreadCurrentUICulture = culture;
LocalizeDictionary.Instance.Culture = culture;

LocalizeDictionary是XAMLMarkupExtensions nuget的一部分,允许立即刷新所有本地化绑定。

不幸的是,由于迁移到NET6并在其中添加了一些异步代码,它停止了正常工作。

它确实改变了当前线程区域性、所有新线程区域性,甚至刷新了当前打开的窗口区域性。

问题是,已经运行的线程似乎没有得到更新,应用程序现在比以前更多地尝试重用它们,而不是创建新的线程。因此,如果我放入断点,比如说一个按钮命令并检查区域性,它仍然显示旧的。为新窗口创建新视图模型也是如此,它似乎是使用旧的区域性创建的。

我已经看到很多答案提到这一行:

FrameworkElement.LanguageProperty.OverrideMetadata(typeof(FrameworkElement), new FrameworkPropertyMetadata(language));

不幸的是,对于整个应用程序,这需要在静态上下文中设置一次,在运行时无法更改(PropertyMetadata is already registered for type 'FrameworkElement'.(。我不认为这真的是问题所在,因为在当前窗口上循环和更改Language属性似乎也是如此。我的问题似乎在于现有的后台线程,而不是WPF元素本身。

我试图找到一种方法来查找所有现有线程,但只获得了带有Process.GetCurrentProcess().Threads的操作系统线程,而没有获得托管线程,因此无法通过该方法更改其区域性。

有没有办法列出所有现有的线程并更改它们的区域性?或者强制WPF在新线程上运行命令,而不是重新使用它们?

由于某些原因,上面的代码更改线程/default/dispatchers/window xml上的区域性是可行的,但当从正常的事件处理程序或命令运行时。

在我的情况下,它是在异步命令中运行的(在ReactiveUI库ReactiveCommand.CreateFromTask((的帮助下(,在该上下文中运行不会保留更改。即使我从该任务内部调用了WPF调度程序,也不会。以下所有事件/命令,甚至绑定的属性getter都将使用旧的区域性进行调用。

所以我无法解释细节,但如果您的文化变化不适用,请检查您正在执行操作的上下文。

此外,在每个窗口上循环也是没有用的。您只需在Application.Current.MainWindow 上设置即可

最新更新