如何随CurrentCulture更新NotifyIcon与ContentControl的UI?
解决WPF语言切换后模态窗口与NotifyIcon未更新的问题
问题场景
我在MainWindow内有作为模态窗口的ContentControl(用户控件)以及NotifyIcon,通过单选按钮事件切换CurrentCulture。当前切换逻辑如下:
初始化与切换方法代码
// Initialization public string LangSwitch { get; private set; } = ""; // Language switch method private void OnEnglishRadioButtonChecked(object sender, RoutedEventArgs e) { LangSwitch = "en-US"; Close(); }
App.xaml.cs代码
public static void ToggleLanguage(object? sender, EventArgs e) { var window = (MainWindow) sender; if (window == null || string.IsNullOrEmpty(window.LangSwitch)) return; window.Closed -= ToggleLanguage; window.Close(); var language = window.LangSwitch; Thread.CurrentThread.CurrentUICulture = new CultureInfo(language); Thread.CurrentThread.CurrentCulture = new CultureInfo(language); Settings.Default.LanguageCode = language; Settings.Default.Save(); window = new MainWindow(); window.Show(); }
切换后MainWindow会刷新并更新为当前文化的文本,但模态窗口和NotifyIcon的UI并未更新,仅重启应用后才会生效。尝试过刷新模态窗口Frame、重新初始化NotifyIcon并释放旧实例、设置Frame内容为默认页面,但都无效。
解决方案
1. 模态窗口本地化更新
模态窗口的本地化绑定需要在文化切换时强制刷新资源与绑定,而非依赖CurrentUICulture的静态变化:
// 在模态窗口(用户控件)类中添加以下方法 public void RefreshLocalization() { var culture = Thread.CurrentThread.CurrentUICulture; // 重新加载对应文化的资源字典 this.Resources.MergedDictionaries.Clear(); var resourceDict = new ResourceDictionary { Source = new Uri($"Resources/Lang.{culture.Name}.xaml", UriKind.Relative) }; this.Resources.MergedDictionaries.Add(resourceDict); // 递归刷新所有控件的绑定 RefreshVisualTree(this); } private void RefreshVisualTree(DependencyObject parent) { for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++) { var child = VisualTreeHelper.GetChild(parent, i); if (child is FrameworkElement element) { // 刷新常见绑定属性 element.GetBindingExpression(FrameworkElement.DataContextProperty)?.UpdateTarget(); element.GetBindingExpression(FrameworkElement.ContentProperty)?.UpdateTarget(); // 遍历所有绑定属性并刷新 foreach (var prop in element.GetLocalValueEnumerator()) { if (BindingOperations.GetBinding(element, prop.Property) != null) { element.GetBindingExpression(prop.Property)?.UpdateTarget(); } } } RefreshVisualTree(child); } }
- 如果模态窗口是已打开的实例,在文化切换后调用
RefreshLocalization(); - 如果是新打开模态窗口,初始化时读取最新
CurrentUICulture加载对应资源字典。
2. NotifyIcon本地化更新
修改NotifyIconManager,添加方法重新加载本地化文本并重建右键菜单:
// 在NotifyIconManager类中添加以下方法 public void RefreshNotifyIconLocalization() { var culture = Thread.CurrentThread.CurrentUICulture; // 更新提示文本 notifyIcon.Text = Resources.ResourceManager.GetString("NotifyIconTooltip", culture); // 重建右键菜单 RebuildContextMenu(); } private void RebuildContextMenu() { notifyIcon.ContextMenuStrip.Items.Clear(); var culture = Thread.CurrentThread.CurrentUICulture; // 根据当前文化重新添加菜单项 notifyIcon.ContextMenuStrip.Items.Add( Resources.ResourceManager.GetString("MenuOpen", culture), null, OnOpenClick ); notifyIcon.ContextMenuStrip.Items.Add( Resources.ResourceManager.GetString("MenuExit", culture), null, OnExitClick ); }
文化切换完成后,调用NotifyIconManager.Instance.RefreshNotifyIconLocalization()即可更新文本。
3. 优化整体切换逻辑
放弃关闭重启MainWindow的方式,直接在当前上下文刷新所有UI:
// 修改App.xaml.cs的ToggleLanguage方法 public static void ToggleLanguage(string languageCode) { var culture = new CultureInfo(languageCode); Thread.CurrentThread.CurrentUICulture = culture; Thread.CurrentThread.CurrentCulture = culture; Settings.Default.LanguageCode = languageCode; Settings.Default.Save(); // 刷新主窗口(需给MainWindow添加类似的RefreshLocalization方法) var mainWindow = Application.Current.MainWindow as MainWindow; mainWindow?.RefreshLocalization(); // 刷新所有已打开的模态窗口 foreach (Window window in Application.Current.Windows) { if (window != mainWindow && window is YourModalWindow modalWindow) { modalWindow.RefreshLocalization(); } } // 刷新NotifyIcon NotifyIconManager.Instance.RefreshNotifyIconLocalization(); }
修改单选按钮事件:
private void OnEnglishRadioButtonChecked(object sender, RoutedEventArgs e) { App.ToggleLanguage("en-US"); }
效果说明
修改后无需重启MainWindow,语言切换时会即时刷新主窗口、模态窗口及NotifyIcon的本地化文本,无需重启应用即可生效。
内容的提问来源于stack exchange,提问作者White_Wolf_DD
相关产品推荐
相关产品推荐

