应用程序具备多语言支持,是实现全球化(Globalization)和本地化(Localization)最重要的功能。
关于全球化和本地化的概念、设计原则、基本流程可参考微软文档
https://docs.microsoft.com/zh-cn/dotnet/framework/wpf/advanced/wpf-globalization-and-localization-overview
目前有多种方案可供选择:
-
使用resx资源文件
-
使用xaml资源文件
-
使用markup扩展
本文介绍学习使用resx文件的一些经验和心得。
resx资源文件通常是嵌入应用的数据,随应用程序一起发布,如果修改资源文件中的数据,需要重新编译。
.NET对多种语言使用“中心–卫星”模式管理多个区域的资源,处于“中心”位置的称为默认资源,处于“卫星”位置的称为特定区域资源。
例如,项目中有个资源文件Resources.resx,这个就是默认资源文件,Resources.en-US.resx、Resources.fr-FR.resx、Resources.zh-CN.resx等就是特定区域的资源文件。
在VS中编译生成应用程序时,编译器会在可执行程序的目录中生成对应特定区域的子目录,子目录中存放区域对应资源的dll文件。
.NET使用ResourcesManager对象管理这些资源文件, ResourceManager从Thread.CurrentUICulture属性中获得当前的区域,然后根据该属性从特定区域中进行查找,如果找到了对应的区域,则使用该区域的资源内容,如果未在特定区域中找到内容,则使用默认的资源。
下面举个简单的例子说明。
代码与数据
新建一个WPF(.NET Framework)桌面应用TestApp,
创建的项目中,VS已经预先建好了一些文件,打开Properties目录下的Resources.resx文件,在其中添加一些字符串资源,并且将访问修饰符改为Public。
然后在Properties目录下新建一个文件名为Resources.en-US.resx的资源文件,在其中添加字符串资源。
修改Properties目录下的Settings.settings文件,增加当前App语言的设置。
编辑MainWindow.xaml前端文件。
首先添加名称空间,并在Grid中添加两个按钮控件。
xmlns:prop="clr-namespace:TestApp.Properties"
<Button Content="{x:Static prop:Resources.btnChnText}" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="75" Click="Button_chn_Click"/>
<Button Content="{x:Static prop:Resources.btnEngText}" HorizontalAlignment="Left" Margin="100,10,0,0" VerticalAlignment="Top" Width="75" Click="Button_eng_Click"/>
编辑MainWindow.xaml.cs后台文件
首先添加引用
using System.Globalization;
然后在MainWindow中添加两个内部成员变量
string _currentCulture = Properties.Settings.Default.Culture;
ResourceManager _rm = new ResourceManager("TestApp.Properties.Resources",
typeof(MainWindow).Assembly);
修改MainWindow的构造函数,在InitializeComponent之前修改当前的Culture。
Thread.CurrentThread.CurrentUICulture
= CultureInfo.CreateSpecificCulture(_currentCulture);
增加两个按钮的响应函数
private void Button_chn_Click(object sender, RoutedEventArgs e)
if (MessageBox.Show(_rm.GetString("strChnQuestion"), "",
MessageBoxButton.YesNo,
MessageBoxImage.Question)
== MessageBoxResult.Yes)
Properties.Settings.Default.Culture = "zh-CN";
Properties.Settings.Default.Save();
private void Button_eng_Click(object sender, RoutedEventArgs e)
if (MessageBox.Show(_rm.GetString("strEngQuestion"), "",
MessageBoxButton.YesNo,
MessageBoxImage.Question)
== MessageBoxResult.Yes)
Properties.Settings.Default.Culture = "en-US";
Properties.Settings.Default.Save();
程序运行后缺省显示中文,点击按钮显示的也是中文的提示。
选择某个语言后,重新启动程序,所有的界面和提示都切换成了目标语言。
这种方法的缺陷在于界面的文字采用静态渲染,运行过程中不会因为语言的切换而改变现实。
如果不考虑程序的执行效率,可以利用Markup的扩展,将界面语言的切换改为动态方式,这样可以在运行中进行语言的切换,而不必重新启动程序。
使用一种语言的多个Resource.resx文件(资源管理器)进行WPF本地化。
如果只想对文本进行本地化,而发现太大而不能满足您的需要,则可以将其用作“一个文件”替代方案,它可以对字符串(而不是图像)进行本地化。
它支持文化的动态变化,这意味着:它允许在运行时更改语言,而无需重新启动应用程序。
用于本地化多个棱镜模块:
ModuleA\Properties\Resources.resx
ModuleA\Properties\Resources.de.resx
ModuleA\Properties\Resources.es.resx
ModuleB\Properties\Resourc
资源在编译期间添加到程序集。如果要将资源嵌入到程序集,则必须将文件添加到项目中,文件会自动拷贝到项目文件夹的Resources文件夹中。如果要嵌入到程序集,还需选中文件,修改其属性“生成操作”(Build Action)为“嵌入的资源”,默认为“内容”。
一旦设置为嵌入的资源,则它就会成为资源清单中程序集的一部分。每一程序集,无论是静态的还是动态的,均包含描述该程序集中各元素彼此如何关联的数据...
xmlns:res=“clr-namespace:双语言测试.Language”
然后,调用资源:
Content="{x:Static res:StringResource.String1}"
3 设置资源的区域性
双语言测试.Langu...
WPF中的二进制资源,就是类似于MFC中在对话框程序中添加的图片、字符串等资源,程序在运行时将其转换成二进制,以供程序使用。
下面以将字符串转换成二进制为例来说明,二进制资源的使用方法:
首先在项目的Properties->Resources.re
sx中添加如下的字符串:
然后在Xmal文件中,添加如下代码:
<Window x:Class="_9_5.MainWindow"
在 WPF 中使用多线程有几种方法:
1. 使用 `BackgroundWorker` 类。这是 WPF 提供的一个内置类,可以在后台线程中执行长时间运行的任务,并提供了方便的事件来监视任务的进度和状态。
2. 使用 `Task` 类。这是 .NET Framework 提供的一个类,可以在后台线程中执行长时间运行的任务,并提供了很多有用的方法来管理和同步多个任务。
3. 使用 `Dispatcher` 类。这是 WPF 提供的一个类,可以用来在不同的线程之间执行操作。例如,如果你有一个后台线程,并且想要在 UI 线程上更新某个 UI 元素,就可以使用 `Dispatcher` 来实现。
示例代码:
private void Button_Click(object sender, RoutedEventArgs e)
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += Worker_DoWork;
worker.RunWorkerCompleted += Worker_RunWorkerCompleted;
worker.RunWorkerAsync();
private void Worker_DoWork(object sender, DoWorkEventArgs e)
// 在后台线程上执行长时间运行的任务
private void Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
// 在 UI 线程上更新 UI 元素