2013年9月10日 星期二

[轉貼] 序列化表單 - 多國語言應用程式

出處:http://www.dotblogs.com.tw/yc421206/archive/2011/02/20/21469.aspx

利用序列化將表單上的設定儲存起來,本篇範例僅儲存控制項的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需要儲存,若用以往的方法來處理相當的累人,由其是增加或減少攔位,若靈活的運用序列化,必然可以節省掉相當多的時間的,不彷考慮下次在您的專案這樣處理吧。

沒有留言:

張貼留言