有朋友詢問如何讓WPF應用能夠提供多語言支持(中文,英文,日文.....),我的建議是:(1)拋棄WinForm時代的資源存儲方式 (2)利用WPF的動態資源特性.
下面簡單介紹一下並打造一個簡單的DEMO:
1,語言資源文件怎樣存儲
我們知道以前(WPF以前)我們將界面上的各國語言分別存儲在.resx類型的文件中,然後利用ResourceManager來得到相應資源並根據當地的CultureInfo來給界面文本賦值.這是可行的.但在WPF中存在的一個問題是:我們必須為每個控件在後台代碼中來Code這些邏輯,因為XAML是找不到.resx類型中的資源的.但WPF中絕大多數界面元素都是在XAML中定義的這是一件很麻煩的事情.所以我們應該拋棄這樣的做法.
WPF中的資源繼承了以前的多種存儲形式,但可以在XAML和C#(或其他)中通行的有兩中,一個是Content,一個是Resource,前者是"內容",既是松散的資源鏈接,後者是被編譯並嵌入的資源,注意,你在設置資源文件屬性的時候會發現還有一個很讓人混淆的Embedded Resource,這也是內嵌的資源,但其被壓縮為二進制形式,既和以前WinForm的內嵌資源相同,Resource和Embedded Resource在編碼上的區別是前者可以通過Uri找到,這是XAML需要的方式,後者可以通過Stream找到,這可以通過編寫c#代碼來查找資源.
所以,在這裡看來Content是我們保存語言資源的良好方式,由於其是松散的資源鏈接,所以為應用程序添加新的語言包時就可以不重新編譯了,只需將對象的語言文件拷貝到指定的文件夾即可.
2,界面元素如何鏈接到語言文本
這是StaticResource 和 DynamicResource要做的事情,比如:
<Button Content="{DynamicResource OK}"/>
至於是使用StaticResource 還是DynamicResource,這取決於你是否要在運行時動態切換,如果僅僅是軟件啟動的時候才切換語言StaticResource就可以了.
3,OK 實戰一下:
3.1 新建項目,並在項目中新建一個Lang文件夾用於保存我們的語言文件
3.2 在Lang文件夾中,新建"ResourceDictionary(WPF)",命名為"DefaultLanguage.xaml",並將其BuildAction設置為Page,這是一個默認語言資源文件,其將被編譯(而不是松散鏈接,這樣可以確保在軟件語言包丟失或沒有某國家或地區的對應語言包時可以有一種默認的界面語言):我們這裡采用英文作為默認語言:
<ResourceDictionary XMLns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
XMLns:x="http://schemas.microsoft.com/winfx/2006/xaml"
XMLns:sys="clr-namespace:System;assembly=mscorlib">
<sys:String x:Key="OK">
OK
</sys:String>
<sys:String x:Key="Cancel">
Cancel
</sys:String>
</ResourceDictionary>
然後,我們添加另一國語言,比如中文,在Lang文件夾中,新建"ResourceDictionary(WPF)",命名為"zh-CN.xaml",並將其BuildAction設置為Content,將CopyToOutputDirctory設置為"if new",這樣,我們的中文語言文件為將被拷貝到應用程序目錄下的Lang目錄下,其他的非默認語言的語言文件都應該采取這種方式.
<ResourceDictionary XMLns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
XMLns:x="http://schemas.microsoft.com/winfx/2006/xaml"
XMLns:sys="clr-namespace:System;assembly=mscorlib">
<sys:String x:Key="OK">
確定
</sys:String>
<sys:String x:Key="Cancel">
取消
</sys:String>
</ResourceDictionary>
3.3 為了讓編碼人員在設計器(比如VS,Blend)中所見即所得地看到界面文本,我們應該將默認語言資源加入到應用程序的資源列表中:
<Application x:Class="LangDemo.App"
XMLns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
XMLns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Window1.xaml"
>
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionarIEs>
<ResourceDictionary Source="lang\DefaultLanguage.xaml"/>
</ResourceDictionary.MergedDictionarIEs>
</ResourceDictionary>
</Application.Resources>
</Application>
這樣我們就可以在設計器中使用這些資源了:
我們可以看到由於我們加載的默認語言是英文,設計器中我們的窗口界面上顯示的是對應的英文文本.
3.4 軟件啟動時加載對應的本地化的語言:
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
LoadLanguage();
}
private void LoadLanguage()
{
CultureInfo currentCultureInfo = CultureInfo.CurrentCulture;
ResourceDictionary langRd = null;
try
{
langRd =
Application.LoadComponent(
new Uri(@"Lang\" + currentCultureInfo.Name + ".xaml", UriKind.Relative))
as ResourceDictionary;
}
catch
&
nbsp;
{
}
if (langRd != null)
{
if (this.Resources.MergedDictionarIEs.Count > 0)
{
this.Resources.MergedDictionarIEs.Clear();
}
this.Resources.MergedDictionarIEs.Add(langRd);
}
}
}
當軟件啟動時,我們根據當地的CultureInfo來加載對應的語言文件(如果該語言文件存在的話),由於界面上的文本不是硬編碼進去的,而是采用DynamicResource,當後台Resource改變時,前台的引用也會動態改變,OK,當軟件啟動後,我們的界面就自動的切換了,我這台電腦上是中文: