[C#.NET][Winform] 序列化表單 - 多國語言應用程式 / Form Serialize - Multiple Languages Application

[C#.NET][Winform] 序列化表單 - 多國語言應用程式 / Form Serialize - Multiple Languages Application

利用序列化將表單上的設定儲存起來,本篇範例僅儲存控制項的Name及Text屬性,如此一來反序列化時再將其資料寫回控制項的Text屬性就能達到多語系的效果,以前也曾經寫過多國語系ttp://www.dotblogs.com.tw/yc421206/archive/2008/12/28/6553.aspx,當時是利用資源檔下去做處理,序列化方式請參考[.NET] 利用 泛型方法 重構 反序列化

 

建立資源檔時必需手動建立控制項的Name,相當累人

image

變更語系時還要特別的小心對應,若這時正在加班陷入精神恍神狀態,對應錯了就麻煩了,雖然不至於導致系統癱瘓,但錯誤終究發生機率還是很高。

image

 

在VB6時代裡常用的ini對應也是一樣要手動自己敲,相當的累人,在.NET世界的序列化,就是一個相當好用的方法,避掉了一些錯誤機會的發生。


實作序列化:

接下來實作一下表單序列化的方式

建立表單要存放的欄位,裡面的 ChildControls 是為了存放 Controls 中的控制項,若你的控制項是擺放在集合控制項內,必須另外把它們撈出來。


public class FormFields 
{ 
    public string Name; 
    public string Text; 
    public List<FormFields> ChildControls = new List<FormFields>(); 
    public FormFields() 
    { 
    } 
    public FormFields(Control Ctrl) 
    { 
        Name = Ctrl.Name; 
        Text = Ctrl.Text; 
    } 
} 

 

 

 

然後再建立一個FormSerialize類別,

Serialize方法:將表單內所有控制項的Name及Text屬性儲存下來。

SerializeControl方法:找出所有控制項並加入ChildControls集合內。

Deserializez方法:打開檔案依控制項Name還原Text屬性。

DeserializeControl方法:找出所有控制項並還原屬性。


public class FormSerialize
{
    public void Serialize(string File, Control root)
    {
        FormFields field = new FormFields(root);
        SerializeControl(field, root);

        XmlSerializer xml = new XmlSerializer(typeof(FormFields));
        TextWriter writer = new StreamWriter(File);
        try
        {
            xml.Serialize(writer, field);
        }
        finally
        {
            writer.Close();
        }
    }
    //遞迴找出所有控制項,加入至集合
    private void SerializeControl(FormFields Field, Control Ctrl)
    {
        foreach (Control ctrl in Ctrl.Controls)
        {
            FormFields field = new FormFields(ctrl);
            Field.ChildControls.Add(field);
            if (ctrl.Controls.Count > 0)
                SerializeControl(field, ctrl);
        }
    }

    public void Deserialize(string File, Control Ctrl)
    {
        XmlSerializer xml = new XmlSerializer(typeof(FormFields));
        FileStream fs = new FileStream(File, FileMode.Open);
        FormFields field = null;
        try
        {
            var o = xml.Deserialize(fs);
            if (o != null)
                field = (FormFields)o;
        }
        finally
        {
            fs.Close();
        }

        //Form
        if (Ctrl.Name == field.Name)
            Ctrl.Text = field.Text;
        DeserializeControl(field, Ctrl);
    }

    //遞迴找出所有控制項,並指定Text屬性
    private void DeserializeControl(FormFields Field, Control Ctrl)
    {
        if (Field == null)
            return;
      
        //Form.Controls
        foreach (FormFields field in Field.ChildControls)
        {
            if (Ctrl.Controls[field.Name] != null)
            {
                Ctrl.Controls[field.Name].Text = field.Text;
                if (field.ChildControls.Count > 0)
                    DeserializeControl(field, Ctrl.Controls[field.Name]);
            }
        }
    }
}

 

 


操作方式:

短短幾行程式碼變可以達到序列化/反序號表單,這是序列化相當實用的一種方法,接下來看看如何操作,

1.設計好一個表單,這時的Text屬性都是中文(或英文)

image

2.呼叫序列化方法FormSerialize.Serialize,儲存表單的資訊。


private void btnSerialize_Click(object sender, EventArgs e)
{
    this._Serialize.Serialize(Cht, this);//序列化中文版
}

 

 

 

3.此時會產生一個中文版的檔案,將它複製一份→變更檔名,然後將內容裡的中文改成英文。

image

 

英文版

image

 

4.語系建立好後,呼叫FormSerialize.Dserialize方法計可以切換語系了,用戶端呼叫完整範例


const string Cht = "resource_ch.xml";
const string Eng = "resource_eng.xml";

FormSerialize _Serialize = new FormSerialize();
private void btnSerialize_Click(object sender, EventArgs e)
{
    this._Serialize.Serialize(Cht, this);//序列化中文版
}

private void btnCht_Click(object sender, EventArgs e)
{
    if (!File.Exists(Cht))
        return;
    this._Serialize.Deserialize(Cht, this);
}

private void btnEng_Click(object sender, EventArgs e)
{
    if (!File.Exists(Eng))
        return;
    this._Serialize.Deserialize(Eng, this);
}

 

 

 

觀察一下反序列化xml檔的變數,變數o可以看到xml結構跟我們定義的 FormFields 是一樣的

image

 


後記:

序列化表單真的是儲存設定檔的一個好選擇,如果你有許多的控制項參數需要定義,這樣的做法真的可以省掉對應的時間,比如在groupBox1控制項裡有一大堆的textBox需要儲存,若用以往的方法來處理相當的累人,由其是增加或減少攔位,若靈活的運用序列化,必然可以節省掉相當多的時間的,不彷考慮下次在您的專案這樣處理吧。FormSerialize.zip

若有謬誤,煩請告知,新手發帖請多包涵


Microsoft MVP Award 2010~2017 C# 第四季
Microsoft MVP Award 2018~2022 .NET

Image result for microsoft+mvp+logo