分享兩種完成Winform順序的多言語支持的多種處理方案。本站提示廣大學習愛好者:(分享兩種完成Winform順序的多言語支持的多種處理方案)文章只能為提供參考,不一定能成為您想要的結果。以下是分享兩種完成Winform順序的多言語支持的多種處理方案正文
因公司業務需求,需求將原有的ERP零碎加上支持繁體言語,但不能改動原有的編碼方式,即:普通順序員感受不到編碼有什麼不同。經過我與幾個同事的多番溝通,確定了以下兩種方案:
方案一:在窗體基類中每次加載並顯示窗體時,會自動遞歸遍歷含文本顯示的控件(Button,CheckBox,GroupBox,Label,LinkLabel,TextBox,StatusStrip,TabPage,ToolStrip,RadioButton,DateTimePicker,DataGridView,CheckedListBox,TreeView,MenuStrip),並依據不同的控件類型的文本屬性調用簡繁轉換辦法停止轉換偏重新設置新的相應文本屬性的內容(比方:繁體內容)
優點:編碼復雜,對普通順序員的編碼無影響(除窗體類的基類由Form類變成MyStyleFormBase類);
缺陷:因每次翻開窗體都需求遍歷控件並停止簡繁轉換,假如界面上的控件較多,則能夠招致翻開窗體較慢,影響用戶體驗,且子控件的文本內容改動時需順序員手動告訴,無法自動感知並轉換。
詳細完成思緒如下:
一.對Form類停止二次封裝(承繼),定義一個MyStyleFormBase類,並在外面參加每次加載並顯示窗體類型時,會自動遞歸遍歷含文本顯示的控件,並依據不同的控件類型的文本屬性調用簡繁轉換辦法停止轉換偏重新設置新的相應文本屬性的內容,這樣當一切的窗體都承繼MyStyleFormBase類時,均默許就完成了遍歷與轉換的進程,順序員無需再次編碼,甚至都無需知道存在遍歷與轉換的進程,從而進步了代碼的復用性,詳細代碼如下:
public class MyStyleFormBase : Form { public MyStyleFormBase() { if (!Thread.CurrentThread.CurrentUICulture.Name.Equals("zh-CHS", StringComparison.OrdinalIgnoreCase)) //假如是簡體,則無需轉換 { base.TextChanged += MyStyleFormBase_TextChanged; base.Shown += MyStyleFormBase_Shown; } } private void MyStyleFormBase_TextChanged(object sender, EventArgs e) { this.Text = LanguageHelper.GetLanguageText(this.Text); } private void MyStyleFormBase_Shown(object sender, EventArgs e) { LanguageHelper.SetControlLanguageText(this); base.ControlAdded += MyStyleFormBase_ControlAdded; } private void MyStyleFormBase_ControlAdded(object sender, ControlEventArgs e) { LanguageHelper.SetControlLanguageText(e.Control); } /// <summary> /// 強迫告訴子控件改動音訊 /// </summary> /// <param name="target"></param> protected virtual void PerformChildrenChange(Control target) { LanguageHelper.SetControlLanguageText(target); } /// <summary> /// 彈出音訊框 /// </summary> /// <param name="text"></param> /// <param name="caption"></param> /// <param name="buttons"></param> /// <param name="icon"></param> /// <param name="defaultButton"></param> /// <returns></returns> protected DialogResult MessageBoxShow(string text, string caption, MessageBoxButtons buttons = MessageBoxButtons.OK, MessageBoxIcon icon = MessageBoxIcon.None, MessageBoxDefaultButton defaultButton = MessageBoxDefaultButton.Button1) { return MessageBox.Show(LanguageHelper.GetLanguageText(text), LanguageHelper.GetLanguageText(caption), buttons, icon, defaultButton); } }
代碼邏輯扼要闡明:
1.當以後UI的文明區域不為中文簡體時(由於本順序自身都是基於簡體開發的),就訂閱窗體顯示事情Shown及窗體標題改動事情TextChanged,作用:當窗體顯示時,則會遍歷控件並轉換為繁體,當標題的文本改動時,也會自動轉換為繁體;
2.當窗體顯示後訂閱窗體的控件添加事情ControlAdded,作用:當窗體顯示後,若後續存在代碼添加控件時,會自動將控件及其子控件停止繁體的轉換,保證一個都不漏;
3.添加一個音訊提示框辦法,目的是彈出音訊窗口前可以將簡體文本轉換成繁體文本;
4.添加一個強迫告訴子控件改動音訊的辦法PerformChildrenChange,當某個控件的文本內容或添加子控件發作時,由於窗體自身無法捕捉到,故需求調用該辦法來遍歷與轉換子控件的文本內容;(覺得這裡不太好,但目前沒有更好的方法,假如大家有更好的方法,歡送留言評論)
二、LanguageHelper:語方轉換公共類(目前僅支持簡繁轉換,依賴於:ChineseConverter.dll)代碼如下:
由於代碼過長,請點擊下載
該類邏輯很復雜,就是從一個父控件開端,遍歷一切的子控件,並依據不同的控件類型將控件相應的文本內容轉換成簡體或繁體,調用辦法:SetControlLanguageText
以上二步就完成了多言語的支持了(精確的說是簡繁轉換),使用到項目中很復雜,只需將窗體默許的基類Form改成:MyStyleFormBase即可,如:public partial class FormTest : MyStyleFormBase
方案二:由控件根據以後區域信息+緩存言語字典直接完成各控件自行轉換
優點:無需遍歷,各控件自行依據區域信息自支轉換,因而效率較高,對普通順序員的編碼無影響(除窗體類的基類由Form類變成MyStyleFormBase類外,還需求運用支持多言語的控件,這些控件均由普通控件二次封裝得來,保存原有的一切屬性及事情);
缺陷:需將一切帶文本顯示的控件(如:Button,CheckBox,GroupBox,Label,LinkLabel,TextBox,StatusStrip,TabPage,ToolStrip,RadioButton,DateTimePicker,DataGridView,CheckedListBox,TreeView)均停止二次封裝,控件一致命名為:MyStyleXXX
觸及的控件較多,編碼絕對復雜;
詳細完成思緒如下:
一.對Form類停止二次封裝(承繼),定義一個MyStyleFormBase類,外面參加對窗體標題停止修正時,能自動停止多言語轉換功用,詳細代碼如下:
public partial class MyStyleFormBase : Form { public MyStyleFormBase() { base.TextChanged += MyStyleFormBase_TextChanged; } private void MyStyleFormBase_TextChanged(object sender, EventArgs e) { if (!Common.IsChsLanguage()) { this.Text = LanguageHelper.GetLanguageText(this.Text); } } /// <summary> /// 彈出音訊框 /// </summary> /// <param name="text"></param> /// <param name="caption"></param> /// <param name="buttons"></param> /// <param name="icon"></param> /// <param name="defaultButton"></param> /// <returns></returns> protected DialogResult MessageBoxShow(string text, string caption = "提示", MessageBoxButtons buttons = MessageBoxButtons.OK, MessageBoxIcon icon = MessageBoxIcon.None, MessageBoxDefaultButton defaultButton = MessageBoxDefaultButton.Button1) { if (!Common.IsChsLanguage()) { text = LanguageHelper.GetLanguageText(text); caption = LanguageHelper.GetLanguageText(caption); } return MessageBox.Show(text, caption, buttons, icon, defaultButton); } }
代碼邏輯很復雜,就是訂閱一個Form.TextChanged事情,以便利依據IsChsLanguage(判別能否為簡體形式)判別不是簡體時,則需停止Form.Text轉換
二.定義多言語支持普通控件及容器控件接口(IMultiLanguageControl、IMultiLanguageContainerControl),詳細代碼如下:(此處僅是為了作一個標准,支持手動設置轉換控件的文本內容)
/// <summary> /// 支持多言語普通控件(無子控件) /// </summary> public interface IMultiLanguageControl { string DefaultLangText { get; } string CurrentLangText { get; set; } } /// <summary> /// 支持多言語容器控件(包括子控件) /// </summary> public interface IMultiLanguageContainerControl { Dictionary<object, string> DefaultLangTexts { get; } Dictionary<object, string> CurrentLangTexts { get; set; } Control this[string ctrlName] { get; set; } void SetItemCurrentLangText(string ctrlName, string langText); event EventHandler<ChildrenAddedEventArgs> ChildrenChanged; } public class ChildrenAddedEventArgs : EventArgs { public Dictionary<object, string> LangTexts { get; private set; } public ChildrenAddedEventArgs() { LangTexts = new Dictionary<object, string>(); } public ChildrenAddedEventArgs(Dictionary<object, string> langTexts) { this.LangTexts = langTexts; } public string this[object key] {get { return LangTexts[key]; } set { LangTexts[key] = value; } }}
三、完成支持多言語普通控件:基於原有規范控件(Button,CheckBox,GroupBox,Label,LinkLabel,TextBox,RadioButton,DateTimePicker)停止二次封裝,完成IMultiLanguageControl接口,各控件代碼如下:
以下是MyStyleButton定義代碼,MyStyleCheckBox、MyStyleGroupBox、MyStyleLabel、MyStyleLinkLabel、MyStyleTextBox、MyStyleRadioButton外面的完成代碼均相反
public partial class MyStyleButton : MyButton, IMultiLanguageControl { static Dictionary<string, string> LanDict = new Dictionary<string, string>(); public MyStyleButton() { } public override string Text { get { if (!DesignMode && System.Threading.Thread.CurrentThread.CurrentUICulture.Name != "zh-CHS") { if (LanDict.ContainsKey(DefaultLangText)) { return CurrentLangText; } else { string langText = LanguageHelper.GetLanguageText(base.Text); LanDict[base.Text] = langText; return langText; } } return base.Text; } set { base.Text = value; } } [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public string DefaultLangText { get { return base.Text; } } [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public string CurrentLangText { get { try { return LanDict[DefaultLangText]; } catch (Exception) { return ""; } } set { if (System.Threading.Thread.CurrentThread.CurrentUICulture.Name != "zh-CHS") { if (LanDict.ContainsKey(DefaultLangText)) { LanDict[DefaultLangText] = value; } else { LanDict.Add(DefaultLangText, value); } } } } }
二次封裝這些控件的目的是:1.暴露一致的屬性,便於直接遍歷並賦值(需手動改動文本內容言語的狀況);2.當文本內容發作改動時,可以依據言語緩存字典,疾速直接的自我簡繁轉換,無需再次遍歷;
四、完成支持多言語容器控件:基於原有規范控件(StatusStrip,TabPage,ToolStrip,DataGridView,CheckedListBox,TreeView)停止二次封裝,完成IMultiLanguageContainerControl接口,各控件代碼如下:
MyStyleDataGridView:
由於代碼過長,請點擊下載
MyStyleTabControl:
由於代碼過長,請點擊下載
二次封裝這些控件的目的是:1.暴露一致的屬性,便於直接遍歷並賦值(僅當直接改動文本內容言語時需求);2.當文本內容或子控件文本內容或新增子控件發作改動時,可以依據言語緩存字典,疾速直接的自我簡繁轉換,無需再次遍歷;
五.LanguageHelper:語方轉換公共類,與方案一原理相反,但絕對方案一要復雜很多,代碼如下:
由於代碼過長,請點擊下載
Common.IsChsLanguage辦法定義如下:
public static bool IsChsLanguage() { return System.Threading.Thread.CurrentThread.CurrentUICulture.Name.Equals("zh-CHS", StringComparison.OrdinalIgnoreCase); }
多言語支持的容器類控件的完成難點是:捕捉子控件文本內容的改動,由於沒有現成的事情或辦法,故需求經過其它的途徑來完成文本內容改時可以停止處置。
以上就是本文的全部內容,有人能夠會說,為何不采用資源文件的方式,緣由文章一掃尾就闡明了,是在原有的零碎上,且不能改動原有的編碼作風,故才花了這麼大的力氣來完成這個簡繁轉換的功用,我公司經指導確認最終采用的方案二。文中若有缺乏,歡送交流,謝謝!
注:控件的完成代碼都貼出來了,大家若需求的話,可以直接COPY走,另外為了零碎平安,簡繁體的零碎截圖我就不貼出來了,大家可以自行測試。