做网站的出路,如何在租用的服务器上部署自己的网站 mysql,商城网站项目策划书,怎样注册网站中文域名文章目录 第一步#xff1a;基础实现#xff0c;资源文件入门第二步#xff1a;依赖属性#xff0c;提升WPF体验第三步#xff1a;多页面复用#xff0c;减少重复代码第四步#xff1a;动态化#xff0c;应对更多字符串总结与反思 作为一名WPF开发者#xff0c;我最近… 文章目录 第一步基础实现资源文件入门第二步依赖属性提升WPF体验第三步多页面复用减少重复代码第四步动态化应对更多字符串总结与反思 作为一名WPF开发者我最近在一个配置工具项目中遇到了国际化需求。起初我只是想让按钮文本支持英文和中文切换但随着页面增多需求复杂化我逐渐摸索出一套从简单到专业化的实现方案。这篇文章记录了我的探索过程从最基础的资源文件开始到多页面复用的优化希望能给有类似需求的开发者一些启发。 第一步基础实现资源文件入门
我的项目是一个基于WPF和MVVM的配置工具界面上有“Save”和“Refresh”两个按钮需要支持英文和中文切换。WPF的国际化通常从资源文件.resx入手于是我先尝试了最简单的方法。
在项目中我创建了一个Resources文件夹添加了两个资源文件
Resources.resx默认英文 save: Saverefresh: Refresh Resources.zh-CN.resx中文 save: 保存refresh: 刷新
在XAML中我尝试直接绑定到资源
Button Content{Binding Source{x:Static local:Resources.save}} /但很快发现这种方式在运行时切换语言时不会更新UI因为静态绑定无法响应动态变化。于是我转向代码隐藏文件在UserControl中定义属性
public partial class PageTemplate : UserControl
{public string Save Resources.ResourceManager.GetString(save);public string Refresh Resources.ResourceManager.GetString(refresh);public PageTemplate(){InitializeComponent();DataContext this;}
}XAML改为
Button Content{Binding Save} /这时候按钮显示了英文但点击“中文”按钮后文本没变。我意识到语言切换需要更新CultureInfo于是引入了一个单例类LanguageManager
public class LanguageManager
{private static readonly LazyLanguageManager _instance new LazyLanguageManager(() new LanguageManager());public static LanguageManager Instance _instance.Value;private CultureInfo _currentCulture new CultureInfo(en-US);public CultureInfo CurrentCulture{get _currentCulture;set{_currentCulture value;Thread.CurrentThread.CurrentUICulture value;}}public string GetString(string key) Resources.ResourceManager.GetString(key, _currentCulture) ?? $[{key}];
}在PageTemplate中使用
private readonly LanguageManager _languageManager LanguageManager.Instance;
public string Save _languageManager.GetString(save);加上切换命令
Button CommandParameterzh-CN Command{Binding SwitchLanguageCommand} Content中文 /public ICommand SwitchLanguageCommand new RelayCommandstring(lang
{_languageManager.CurrentCulture new CultureInfo(lang);
});然而切换后UI还是没更新。我调试发现虽然CultureInfo变了但绑定没有刷新。加上INotifyPropertyChanged后问题解决
public partial class PageTemplate : UserControl, INotifyPropertyChanged
{private readonly LanguageManager _languageManager LanguageManager.Instance;public string Save _languageManager.GetString(save);public PageTemplate(){InitializeComponent();DataContext this;_languageManager.PropertyChanged (s, e) OnPropertyChanged(null);}public event PropertyChangedEventHandler PropertyChanged;protected void OnPropertyChanged(string propertyName) PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}终于切换语言时按钮文本正常更新了
第二步依赖属性提升WPF体验
虽然基础功能实现了但这种只读属性方式让我觉得不够“WPF”。在WPF中依赖属性更适合绑定场景。于是我改用依赖属性
public static readonly DependencyProperty SaveProperty DependencyProperty.Register(nameof(Save), typeof(string), typeof(PageTemplate), new PropertyMetadata(string.Empty));public string Save
{get (string)GetValue(SaveProperty);set SetValue(SaveProperty, value);
}public PageTemplate()
{InitializeComponent();DataContext this;UpdateLocalizedStrings();_languageManager.PropertyChanged (s, e) UpdateLocalizedStrings();
}private void UpdateLocalizedStrings()
{Save _languageManager.GetString(save);Refresh _languageManager.GetString(refresh);
}这样绑定更符合WPF的习惯而且UI更新更可靠。下一步我把语言切换按钮改成了下拉框
ComboBox ItemsSource{Binding Languages}DisplayMemberPathDisplayNameSelectedValuePathCultureNameSelectedValue{Binding SelectedLanguage, ModeTwoWay}/public ListLanguageOption Languages { get; } new ListLanguageOption
{new LanguageOption(English, en-US),new LanguageOption(中文, zh-CN)
};public static readonly DependencyProperty SelectedLanguageProperty DependencyProperty.Register(nameof(SelectedLanguage), typeof(string), typeof(PageTemplate),new PropertyMetadata(en-US, OnSelectedLanguageChanged));public string SelectedLanguage
{get (string)GetValue(SelectedLanguageProperty);set SetValue(SelectedLanguageProperty, value);
}private static void OnSelectedLanguageChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{var page (PageTemplate)d;page._languageManager.CurrentCulture new CultureInfo((string)e.NewValue);
}这让界面更友好用户体验也提升了。
第三步多页面复用减少重复代码
项目发展到有多个页面时我发现每个页面都重复定义Save、Refresh和语言切换逻辑太繁琐了。我决定把国际化集中化先创建了一个基类
public class BaseViewModel : INotifyPropertyChanged
{protected readonly LanguageService _languageService LanguageService.Instance;public string Save _languageService.GetString(save);public string Refresh _languageService.GetString(refresh);public event PropertyChangedEventHandler PropertyChanged;protected void OnPropertyChanged(string propertyName) PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}LanguageService接管了语言管理
public class LanguageService : INotifyPropertyChanged
{private static readonly LazyLanguageService _instance new LazyLanguageService(() new LanguageService());public static LanguageService Instance _instance.Value;private CultureInfo _currentCulture new CultureInfo(en-US);public CultureInfo CurrentCulture{get _currentCulture;set{_currentCulture value;Thread.CurrentThread.CurrentUICulture value;OnPropertyChanged(null);}}public string GetString(string key) Resources.ResourceManager.GetString(key, _currentCulture) ?? $[{key}];public ListLanguageOption Languages { get; } new ListLanguageOption{new LanguageOption(English, en-US),new LanguageOption(中文, zh-CN)};public string SelectedLanguage{get _currentCulture.Name;set CurrentCulture new CultureInfo(value);}public event PropertyChangedEventHandler PropertyChanged;protected void OnPropertyChanged(string propertyName) PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}页面只需继承BaseViewModel
public class PageTemplateViewModel : BaseViewModel { }
public partial class PageTemplate : UserControl
{public PageTemplate(){InitializeComponent();DataContext new PageTemplateViewModel();}
}XAML绑定到全局服务
ComboBox ItemsSource{Binding Languages, Source{x:Static services:LanguageService.Instance}}SelectedValue{Binding SelectedLanguage, Source{x:Static services:LanguageService.Instance}, ModeTwoWay}/第四步动态化应对更多字符串
页面越来越多字符串也从save、refresh扩展到title、user等十几个。我不想在BaseViewModel中为每个字符串写属性于是尝试了动态方案
public class BaseViewModel : INotifyPropertyChanged
{protected readonly LanguageService _languageService LanguageService.Instance;public dynamic Strings new LocalizedStrings(_languageService);public BaseViewModel(){_languageService.PropertyChanged (s, e) OnPropertyChanged(nameof(Strings));}public event PropertyChangedEventHandler PropertyChanged;protected void OnPropertyChanged(string propertyName) PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}public class LocalizedStrings : DynamicObject
{private readonly LanguageService _languageService;public LocalizedStrings(LanguageService languageService){_languageService languageService;}public override bool TryGetMember(GetMemberBinder binder, out object result){result _languageService.GetString(binder.Name.ToLower());return true;}
}XAML改为
Button Content{Binding Strings.save} /
TextBlock Text{Binding Strings.title} /现在无论有多少字符串我只需在资源文件里添加键值对代码完全不用改动。这种方式让我从繁琐的属性定义中解放出来。
总结与反思
从最初的简单资源文件到依赖属性再到多页面复用最后用动态对象优化我的国际化之旅走了不少弯路但每一步都让我更理解WPF和MVVM的精髓
起步简单资源文件和基本绑定能快速实现单页面国际化。提升体验依赖属性和下拉框让切换更自然。复用为王集中化管理避免重复劳动。动态扩展用动态对象应对未来需求。
如果你的项目也有国际化需求不妨从基础开始根据规模逐步优化。你遇到过哪些国际化难题欢迎留言分享