动态本地化与MVVM绑定技术

在现代软件开发中,应用程序往往需要支持多语言,以满足不同地区用户的需求。本地化是实现这一目标的关键技术之一。本地化不仅涉及到翻译文本,还包括调整日期、货币和数字格式等。本文将介绍一种动态本地化解决方案,该方案允许在应用程序发布后更改字符串资源或添加新的语言支持,而无需重新编译应用程序。此外,本文还将探讨如何在MVVM(Model-View-ViewModel)模式下实现数据绑定。

网络上有许多优秀的文章详细介绍了.NET中的字符串资源和本地化技术。本文的目标是开发一种本地化解决方案,该方案能够在应用程序发布后更改字符串资源或添加新的语言支持。同时,希望尽可能利用.NET内置的资源处理组件,特别是ResourceManager类。通过MSDN和Visual Studio IntelliSense搜索,发现了CreateFileBasedResourceManager方法,该方法允许在运行时导入外部资源文件。MSDN文章还提到可以采用自定义资源读取器来解析资源,这似乎是完美的解决方案,但文章没有详细说明如何实现。

使用代码

首先,定义了自定义的ResourceSet和ResourceReader对象,它们负责理解和解析外部资源文件。

以下是自定义ResourceSet类的实现。这个类非常简单,它只是返回自定义资源读取器类的实例。

public class StringsResourceSet : ResourceSet { public StringsResourceSet(string fileName) : base(new StringResourceReader(fileName)) { } public override Type GetDefaultReader() { return typeof(StringResourceReader); } }

以下是自定义ResourceReader类的实现,它负责读取字符串资源。

public class StringResourceReader : IResourceReader { string _fileName; public StringResourceReader(string resourceFileName) { _fileName = resourceFileName; } IEnumerator IEnumerable.GetEnumerator() { return this.GetEnumerator(); } public void Close() { throw new NotImplementedException(); } public IDictionaryEnumerator GetEnumerator() { Hashtable htLanguage = new Hashtable(); using (StreamReader sr = new StreamReader(_fileName)) { while (!sr.EndOfStream) { string[] lineParams = sr.ReadLine().Split('='); htLanguage.Add(lineParams[0], lineParams[1]); } } return htLanguage.GetEnumerator(); } public void Dispose() { throw new NotImplementedException(); } }

在这种方法中,资源文件只是包含资源键和值的文本文件,键和值之间用等号分隔,例如:RESOURCEKEY=resourcevalue。通过更改GetEnumerator的实现,资源文件可以是任何格式。在之前提到的文章中,作者使用了SQL数据库。

ResourceViewModel

这里是视图模型类,它还负责基于上述资产初始化资源管理器类。

public class ResourceViewModel { ResourceManager rm; public ResourceViewModel() { rm = ResourceManager.CreateFileBasedResourceManager( "Strings", "Strings", typeof(StringsResourceSet)); } public ResourceManager Manager { get { return rm; } } public string this[string name] { get { return rm.GetString(name); } } public void SetDefaultCulture(CultureInfo culture) { Type type = typeof(CultureInfo); try { type.InvokeMember("s_userDefaultCulture", BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Static, null, culture, new object[] { culture }); type.InvokeMember("s_userDefaultUICulture", BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Static, null, culture, new object[] { culture }); } catch { } try { type.InvokeMember("m_userDefaultCulture", BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Static, null, culture, new object[] { culture }); type.InvokeMember("m_userDefaultUICulture", BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Static, null, culture, new object[] { culture }); } catch { } } }

在XAML中,可以通过索引器属性支持绑定,如下所示:

<TextBlock FontSize="50" Text="{Binding Path=[TESTSTRING]}"/>

XAML绑定访问器

这里是支持XAML绑定的提示/技巧。将ResourceManager GetString方法包装在索引器属性中,XAML支持绑定到索引器属性。

窗口类中的视图模型初始化

ResourceViewModel viewModel = new ResourceViewModel(); public Window1() { InitializeComponent(); DataContext = viewModel; if (!String.IsNullOrEmpty(Properties.Settings.Default.CultureInfo)) { viewModel.SetDefaultCulture(CultureInfo.CreateSpecificCulture(Properties.Settings.Default.CultureInfo)); } }
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485