点击按钮后如何切换WPF应用的Culture并刷新视图?
问题分析
这个问题我之前也碰到过——WPF里用x:Static绑定资源文件字符串时,切换Culture后不会自动更新,因为静态资源是在控件初始化时就解析完成的,不会监听后续的Culture变化。而你绑定SelectedLanguage的标签能更新,是因为你触发了PropertyChanged通知,WPF会重新读取这个属性值。下面给你几个可行的解决方案:
解决方案1:重新加载应用程序资源
当你切换Culture后,强制WPF重新加载资源文件,让所有静态绑定的资源字符串重新解析。你可以在ChangeLanguage方法的末尾添加这段代码:
if (culture != null) { Thread.CurrentThread.CurrentCulture = culture; Thread.CurrentThread.CurrentUICulture = culture; // 重新加载应用程序级资源(如果你的资源是放在App.xaml里的) Application.Current.Resources.Clear(); Application.Current.Resources.MergedDictionaries.Add(new ResourceDictionary { Source = new Uri("App.xaml", UriKind.Relative) }); // 或者如果是窗口级资源,重新初始化当前窗口(适合小型应用) var currentWindow = Application.Current.MainWindow; Application.Current.MainWindow = new MainWindow(); currentWindow.Close(); Application.Current.MainWindow.Show(); }
解决方案2:用动态绑定替代x:Static
x:Static是静态解析的,换成ObjectDataProvider实现动态绑定,这样Culture变化时资源字符串会自动更新。
首先在窗口的Resources里定义ObjectDataProvider:
<Window.Resources> <ObjectDataProvider x:Key="StringsRes" ObjectType="{x:Type res:Strings}" /> </Window.Resources>
然后修改所有控件的绑定方式,替换原来的x:Static:
<Label Content="{Binding Source={StaticResource StringsRes}, Path=ProjectName}" Grid.Column="0" Grid.Row="1" /> <Button Name="btnNL" Content="{Binding Source={StaticResource StringsRes}, Path=BtnPushMe}" Command="{Binding PushMe}" CommandParameter="NL" Width="100" Height="45" Grid.Column="1" Grid.Row="0"/> <Button Name="btnEN" Content="{Binding Source={StaticResource StringsRes}, Path=BtnPushMe}" Command="{Binding PushMe}" CommandParameter="EN" Width="100" Height="45" Grid.Column="2" Grid.Row="0"/>
这样切换Culture后,WPF会自动感知资源文件的变化,不需要额外刷新操作。
解决方案3:遍历可视化树刷新所有绑定
如果不想修改XAML结构,可以写一个工具方法,遍历所有控件并手动刷新绑定。在ChangeLanguage方法末尾调用这个方法:
private void RefreshAllBindings(DependencyObject root) { foreach (DependencyObject child in LogicalTreeHelper.GetChildren(root)) { // 刷新当前控件的所有绑定 foreach (LocalValueEntry entry in child.GetLocalValueEnumerator()) { if (BindingOperations.GetBinding(child, entry.Property) != null) { BindingExpression expr = BindingOperations.GetBindingExpression(child, entry.Property); expr?.UpdateTarget(); } } // 递归刷新子控件 RefreshAllBindings(child); } }
然后在ChangeLanguage里调用:
if (culture != null) { Thread.CurrentThread.CurrentCulture = culture; Thread.CurrentThread.CurrentUICulture = culture; SendPropertyChanged("SelectedLanguage"); // 传入当前主窗口实例刷新所有绑定 RefreshAllBindings(Application.Current.MainWindow); }
额外优化建议
看你的ViewModel代码还有几个小问题可以调整:
PushMe命令里的SendPropertyChanged("ChangeLanguage")是多余的,ChangeLanguage是方法不是属性,不需要通知;SelectedLanguage的getter直接取Language[0],如果Language为空会报错,建议加个空判断:
public string SelectedLanguage { get { return Language?.FirstOrDefault() ?? "NL"; } }
内容的提问来源于stack exchange,提问作者Remco
相关产品推荐
相关产品推荐

