WPF多語言化的實現

Metro插件系統系列就暫時停一下,此次咱們討論一下WPF的資源本地化實現,主要用到的:CultureInfo,ResourceManger,MarkupExtension,RESX文件,這些都是.NET框架提供的。html

項目結構:編程

運行結果:數組

可在程序運行時,實時切換語言框架

CultureInfoide

  CultureInfo類表示有關特定區域性的信息,包括區域性的名稱、書寫體系和使用的日曆,以及有關對經常使用操做(如格式化日期和排序字符串)提供信息的區域性特定對象的訪問。CultureInfo類的實例化通常有兩個途徑,以下所示: CultureInfo culture = CultureInfo. CreateSpecificCulture (name); CultureInfo culture = new CultureInfo(name);函數

兩者的區別是,使用第一種方法,只能建立固定區域性或特定區域性的CultureInfo實例。若是name爲空字符串,則創建固定區域性的實例,若是name爲非特定區域性,那麼創建name 關聯的默認特定區域性的 CultureInfo實例。第二種方法,則是創建一個name所指定的區域性的CultureInfo實例,它能夠是固定的,非特定的或特定區域性的。測試

Thread類的CurrentCulture屬性用來獲取或設置當前線程的區域性。它必須被設置爲特定區域性。 Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");若是Thread.CurrentThread.CurrentCulture = new CultureInfo("en ");就會報錯!this

Thread類的CurrentUICulture屬性用來獲取或設置資源管理器使用的當前區域性以便在運行時查找區域性特定的資源。spa

ResourceManger插件

  ResourceManger類能夠查找區域性特定的資源,當本地化資源不存在時提供代用資源,並支持資源序列化。經常使用的ResourceManager的構造函數是public ResourceManager(string,Assembly)。其含義是初始化 ResourceManager類的新實例,它使用指定的根名稱從給定的Assembly中查找資源文件。所謂根名稱是例如名爲「MyResource.en-US.resources」的資源文件的根名稱爲「MyResource」。在根名稱的表達中能夠加上命名空間,如「MyWebSite.Resource.UserFolder. MyResource」。而Assembly能夠是須要調用資源文件的頁面所在的Assembly,如typeof(MyPage).Assembly。ResourceManager類的GetString方法用來得到資源文件中的指定鍵的值。舉例:當已設置了線程的CurrentUICulture屬性以後按以下方法。 ResourceManager rm = new ResourceManager("items", Assembly.GetExecutingAssembly()); String str = rm.GetString("welcome");

若是想按照指定的區域性來得到資源則按照以下寫法: ResourceManager rm = new ResourceManager("items", Assembly.GetExecutingAssembly()); CultureInfo ci = Thread.CurrentThread.CurrentCulture; String str = rm.GetString("welcome",ci);

MarkupExtension

  Markup Extensions 與TypeConverter 差很少,容許擴展Xaml表達式,把Xaml中的文本轉換成相應的對象/對象程序。

在上述例子中,x:Null, x:Static, Binding 都是Markup Extension.
微軟已經提供了至關多的擴展,而且咱們還能夠自定義擴展類型。
----------------------------------------------------------------------------------------------------

微軟定義的Markup Extension
全部的Extensions都必須派生於:

  publicabstractclass MarkupExtension  publicabstractobject ProvideValue(IServiceProvider serviceProvider);  }

特定於 WPF 的標記擴展 WPF 編程中最經常使用的標記擴展是支持資源引用的標記擴展(StaticResource 和 DynamicResource)以及支持數據綁定的標記擴展 (Binding)。

1. StaticResource 經過替換已定義資源的值來爲 XAML 屬性提供值。

2. DynamicResource 經過將值推遲爲對資源的運行時引用來爲 XAML 屬性提供值。動態資源引用強制在每次訪問此類資源時都從新進行查找。

3. Binding 按應用於元素的數據上下文來爲屬性提供數據綁定值。此標記擴展相對複雜,由於它會啓用大量內聯語法來指定數據綁定。

4. RelativeSource 爲能夠在運行時元素樹中定位若干可能關係的 Binding 提供源信息。對於在多用途模板中建立的綁定,或在未充分了解周圍的元素樹的狀況下以代碼建立的綁定,上述標記擴展會提供專用源。

5. TemplateBinding,控件模板能夠經過它使用來自要利用該模板的類的對象模型定義屬性中的模板化屬性的值。有關詳細信息,請參見 TemplateBinding 標記擴展。

XAML 定義的標記擴展

  有幾個標記擴展並不是是 XAML 的 WPF 應用程序所特有的,而是屬於 XAML 語言的規範和命名空間的一部分。它們一般由語法中的 x: 前綴標識,如您在常見用法中所見到的同樣。這些標記擴展的 WPF 實現使用相同的 MarkupExtension 基類來提供實現。

x:Type 爲命名類型提供 Type 對象。此標記擴展最經常使用於樣式和模板。 x:Static 從不直接屬於屬性值類型、但能夠計算爲該類型的值類型代碼實體中生成靜態值。 x:Null 將 null 指定爲 XAML 屬性的值。 x:Array: 在特地不使用基元素和控件模型提供的集合支持的狀況下,x:Array 爲 XAML 語法中常規數組的建立提供支持。

StringResourceExtension

複製代碼
//=================================================================================
//
//        Copyright (C) 20013-2014    
//        All rights reserved
//        
//        description : 本文博客園首發,若是您想轉載本博客,請註明出處,感謝支持  
//        created by Zengg
//        http://www.cnblogs.com/01codeworld/
//        Email:281365330@qq.com
//==================================================================================
namespace MultilanguageTest
{
    [MarkupExtensionReturnType(typeof(BindingExpression))]
    public class StringResourceExtension : MarkupExtension, INotifyPropertyChanged
    {
      /// <summary>
        /// 資源的名稱,與資源文件StringResource.resx對應
      /// </summary>
        [ConstructorArgument("key")]
        public string Key
        {
            get;
            set;
        }
        string _DefaultValue;
        /// <summary>
        /// 默認值,爲了使在設計器的狀況時把默認值綁到設計器
        /// </summary>
        public string DefaultValue
        {
            get
            {
                return _DefaultValue;
            }
            set
            {
                _DefaultValue = value;
            }
        }
        string _Value;
        /// <summary>
        /// 資源的具體內容,經過資源名稱也就是上面的Key找到對應內容
        /// </summary>
        public string Value
        {
            get
            {
                ///若是爲設計器模式,本地的資源沒有實例化,咱們不能從資源文件獲得內容,因此從KEY或默認值綁定到設計器去
                if (GlobalClass.InDesignMode)
                {
                    if (Key != null && DefaultValue != null)
                        return DefaultValue;
                    if (Key == null && DefaultValue != null)
                        return DefaultValue;
                    if (Key != null && DefaultValue == null)
                        return Key;
                    if (Key == null && DefaultValue == null)
                        return "NULL";
                }
                else
                {
                    if (Key != null)
                    {
                        string strResault=null ;
                        try
                        {
                            strResault = GlobalClass.GetString(Key);
                        }
                        catch
                        {
                        }
                        if (strResault == null)
                        {
                            strResault = _DefaultValue;
                        }
                        return strResault;
                    }
                }
                return _Value;
            }
            set
            {
                _Value = value;
            }
        }
        public StringResourceExtension(string key)
            : this()
        {
            Key = key;
            GlobalClass.LanguageChangeEvent += new EventHandler<EventArgs>(Language_Event);
        }
        public StringResourceExtension(string key, string DefaultValue)
            : this()
        {
            Key = key;
            _DefaultValue = DefaultValue;
            GlobalClass.LanguageChangeEvent += new EventHandler<EventArgs>(Language_Event);
     
        }
        public StringResourceExtension()
        {
        }
        /// <summary>
        /// 每一標記擴展實現的 ProvideValue 方法能在可提供上下文的運行時使用 IServiceProvider。而後會查詢此 IServiceProvider 以獲取傳遞信息的特定服務
        ///當 XAML 處理器在處理一個類型節點和成員值,且該成員值是標記擴展時,它將調用該標記擴展的 ProvideValue 方法並將結果寫入到對象關係圖或序列化流,XAML 對象編寫器將服務環境經過 serviceProvider 參數傳遞到每一個此類實現。
        /// </summary>
        /// <param name="serviceProvider"></param>
        /// <returns></returns>
        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            IProvideValueTarget target = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;

            Setter setter = target.TargetObject as Setter;
            if (setter != null)
            {
                return new Binding("Value") { Source = this, Mode = BindingMode.OneWay };
            }
            else
            {
                Binding binding = new Binding("Value") { Source = this, Mode = BindingMode.OneWay };
                return binding.ProvideValue(serviceProvider);
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;

        static readonly System.ComponentModel.PropertyChangedEventArgs
            valueChangedEventArgs = new System.ComponentModel.PropertyChangedEventArgs("Value");

        protected void NotifyValueChanged()
        {
            if (PropertyChanged != null)
                PropertyChanged(this, valueChangedEventArgs);
        }
        /// <summary>
        /// 語言改變通知事件,當程序初始化的時候會綁定到全局的GlobalClass.LanguageChangeEvent事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Language_Event(object sender, EventArgs e)
        {
            //通知Value值已經改變,需從新獲取
            NotifyValueChanged();
        }
    }
}
複製代碼

Resource  [BY Zengg]

複製代碼
//=================================================================================
//
//        Copyright (C) 20013-2014    
//        All rights reserved
//        
//        description : 本文博客園首發,若是您想轉載本博客,請註明出處,感謝支持  
//        created by Zengg
//        http://www.cnblogs.com/01codeworld/
//        Email:281365330@qq.com
//==================================================================================
namespace MultilanguageTest
{
    public interface IResource
    {
        string GetString(string name);
        CultureInfo CurrentCulture { set; }
    }
    public class Resource : IResource
    {
        private ResourceManager stringResource;
        //咱們這樣設置的時候ResourceManager會去查找MultilanguageTest.StringResource.en-us.resx,若是沒有會查找MultilanguageTest.StringResource.resx
        private CultureInfo culture = new CultureInfo("en-us");
        public Resource()
        {
           //MultilanguageTest.StringResource是根名稱,該實例使用指定的System.Reflection.Assmbly查找從指定的跟名稱導出的文件中包含的資源
            stringResource = new ResourceManager("MultilanguageTest.StringResource", typeof(Resource).Assembly);
        }
        /// <summary>
        /// 經過資源名稱獲取資源內容
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public string GetString(string name)
        {
            return stringResource.GetString(name, culture);
        }
        /// <summary>
        /// 改變當前的區域信息,ResourceManager能夠經過當前區域信息去查找.resx文件
        /// </summary>
        public CultureInfo CurrentCulture
        {
            set
            {
                culture = value;
            }
        }
    }
}
複製代碼

GlobalClass

複製代碼
//=================================================================================
//
//        Copyright (C) 20013-2014    
//        All rights reserved
//        
//        description : 本文博客園首發,若是您想轉載本博客,請註明出處,感謝支持  
//        created by Zengg
//        http://www.cnblogs.com/01codeworld/
//        Email:281365330@qq.com
//==================================================================================
namespace MultilanguageTest
{
    /// <summary>
    /// 全局類
    /// </summary>
    public static class GlobalClass
    {
        static bool? inDesignMode = null;
        /// <summary>
        /// 判斷是設計器仍是程序運行
        /// </summary>
        public static bool InDesignMode
        {
            get
            {
                if (inDesignMode == null)
                {
#if SILVERLIGHT
                    inDesignMode = DesignerProperties.IsInDesignTool;
#else
                    var prop = DesignerProperties.IsInDesignModeProperty;
                    inDesignMode = (bool)DependencyPropertyDescriptor.FromProperty(prop, typeof(FrameworkElement)).Metadata.DefaultValue;

                    if (!inDesignMode.GetValueOrDefault(false) && Process.GetCurrentProcess().ProcessName.StartsWith("devenv", StringComparison.Ordinal))
                        inDesignMode = true;
#endif
                }

                return inDesignMode.GetValueOrDefault(false);
            }
        }
        /// <summary>
        /// 語言改變通知事件
        /// </summary>
        public static EventHandler<EventArgs> LanguageChangeEvent;
        static Resource StringResource;
        static GlobalClass()
        {
            StringResource = new Resource();
        }
        /// <summary>
        /// 獲取資源內容
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public static string GetString(string key)
        {
           return StringResource.GetString(key);
        }
        /// <summary>
        /// 改變語言
        /// </summary>
        /// <param name="language">CultureInfo列表(http://www.csharpwin.com/csharpspace/8948r7277.shtml)</param>
        public static void ChangeLanguage(string language)
        {
            CultureInfo culture = new CultureInfo(language);
            Thread.CurrentThread.CurrentCulture = culture;
            Thread.CurrentThread.CurrentUICulture = culture;

            StringResource.CurrentCulture = culture;

            if (LanguageChangeEvent != null)
            {
                LanguageChangeEvent(null, null);
            }
        }
    }
}
複製代碼

MainWindow.xaml

複製代碼
<Window x:Class="MultilanguageTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:MultilanguageTest"
        Title="MainWindow" Height="350" Width="525">
    <Grid >
        <StackPanel Margin="43,54,411,0">
            <TextBlock Text="{local:StringResource test1,DefaultValue=測試一}"></TextBlock>
            <TextBlock Text="{local:StringResource test2,DefaultValue=測試二}"></TextBlock>
            <TextBlock Text="{local:StringResource test3,DefaultValue=測試三}"></TextBlock>
            <TextBlock Text="{local:StringResource test4,DefaultValue=測試四}"></TextBlock>
        </StackPanel>
   
        <Button Content="{local:StringResource btnChina,DefaultValue=中文}" HorizontalAlignment="Left" Margin="389,90,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click_1"/>
        <Button Content="{local:StringResource btnEnglish,DefaultValue=英文}" HorizontalAlignment="Left" Margin="389,117,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click_2"/>
    </Grid>
</Window>
複製代碼

  綁定到某個對象的用法就是,如{local:StringResource test1,DefaultValue=測試一},test1是當前資源的資源名稱,默認值就是在設計器上顯示的內容。

源碼地址:http://pan.baidu.com/share/link?shareid=3361221912&uk=554439928

若是您看了本篇博客,以爲對您有所收穫,請點擊右下角的 [推薦]

若是您想轉載本博客,請註明出處

若是您對本文有意見或者建議,歡迎留言

感謝您的閱讀,請關注個人後續博客 Zengg

做者:Zengg 出處:http://www.cnblogs.com/01codeworld/ 本文版權歸做者和博客園共有,歡迎轉載,但未經做者贊成必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接,不然保留追究法律責任的權利。

相關文章
相關標籤/搜索