如何在代码中创建类似{lex:LocTextUpper XXX}的本地化绑定?
其实这个需求在WPF里完全可以实现,核心就是利用资源文件(.resx)结合数据绑定,哪怕是纯代码创建的控件,也能像XAML里那样自动响应区域性变更。下面分步骤给你说怎么做:
1. 准备本地化资源文件
首先你得有标准的.resx资源文件,比如Strings.resx(默认语言),然后创建对应区域性的文件比如Strings.zh-CN.resx、Strings.en-US.resx,里面存好要本地化的字符串键值对,比如Greeting对应"你好"和"Hello"。
2. 用代码绑定资源到控件
在代码里创建控件时,不要直接给Content或Text赋值静态字符串,而是用Binding绑定到资源文件的属性,同时要确保绑定能监听区域性变化。这里有两种常用方式:
方式一:封装可通知的本地化管理类
默认的.resx生成的类是静态的,没法通知属性变化,所以我们可以自己封装一个单例类,实现INotifyPropertyChanged,当区域性变更时触发属性更新:
public class LocalizationManager : INotifyPropertyChanged { public static LocalizationManager Instance { get; } = new LocalizationManager(); public string Greeting => Strings.Greeting; public string ConfirmText => Strings.Confirm; // 其他需要本地化的属性... public event PropertyChangedEventHandler? PropertyChanged; // 当区域性变更时调用这个方法,通知所有绑定控件更新 public void OnCultureChanged() { // 可以逐个触发属性变更,或者用string.Empty触发所有属性更新 PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(string.Empty)); } }
然后在代码创建控件时绑定:
var greetingLabel = new Label(); greetingLabel.SetBinding(ContentProperty, new Binding(nameof(LocalizationManager.Greeting)) { Source = LocalizationManager.Instance, Mode = BindingMode.OneWay }); var confirmBtn = new Button(); confirmBtn.SetBinding(ContentProperty, new Binding(nameof(LocalizationManager.ConfirmText)) { Source = LocalizationManager.Instance, Mode = BindingMode.OneWay });
当你切换区域性(比如Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-US");),只要调用LocalizationManager.Instance.OnCultureChanged();,所有绑定的控件就会自动更新文本了。
方式二:使用DynamicResource绑定资源字典
另一种方式是把本地化字符串放到资源字典里,然后用DynamicResource绑定,这样当区域性变更时替换资源字典,控件会自动更新。
首先,在App.xaml或者专门的资源文件里定义不同区域性的资源字典:
<!-- 中文资源字典 --> <ResourceDictionary x:Key="ZhCnResources"> <system:String x:Key="Greeting">你好</system:String> <system:String x:Key="Confirm">确认</system:String> </ResourceDictionary> <!-- 英文资源字典 --> <ResourceDictionary x:Key="EnUsResources"> <system:String x:Key="Greeting">Hello</system:String> <system:String x:Key="Confirm">Confirm</system:String> </ResourceDictionary>
然后在代码里创建控件时用DynamicResource:
var greetingLabel = new Label(); greetingLabel.SetResourceReference(ContentProperty, "Greeting"); var confirmBtn = new Button(); confirmBtn.SetResourceReference(ContentProperty, "Confirm");
当切换区域性时,替换当前的资源字典:
private void SwitchToEnglish() { Application.Current.Resources.MergedDictionaries.Clear(); if (Application.Current.Resources["EnUsResources"] is ResourceDictionary enDict) { Application.Current.Resources.MergedDictionaries.Add(enDict); } }
这种方式不需要手动触发属性变更,WPF会自动检测资源字典的变化并更新控件。
3. 额外技巧:自动监听区域性变更
如果你想更省心,可以在App启动时监听区域性变更事件,自动触发更新。比如在App.xaml.cs里:
protected override void OnStartup(StartupEventArgs e) { base.OnStartup(e); // 监听系统区域性变更 CultureInfo.CurrentCultureChanged += (s, args) => { LocalizationManager.Instance.OnCultureChanged(); // 或者替换资源字典的逻辑,根据你的方式选择 }; }
这样只要系统的区域性变了,你的控件文本就会自动更新,完全不用手动处理。
内容的提问来源于stack exchange,提问作者Gábor

