[C#.NET][Winform][ADO.NET] comboBox 控制項與 enum 的 Data Binding

  • 11487
  • 0
  • 2013-08-16

[C#.NET][Winform][ADO.NET] comboBox 控制項與 enum 的 Data Binding

當PM提需求

1.表單參數設定需要有UI介面讓使用者填寫,並存成設定檔,下次程式開啟時要載入這個設定檔

2.comboBox控制項要有自己的下拉選單資料,以免使用者填錯資料。

3.使用者變更選單內容時可以資料來源也跟著更新。

 

心理想著:


1.很簡單,相關資料可參考

[ADO.NET][.NET] 利用序列化+資料繫結 儲存表單參數
[ADO.NET][.NET] 類別(Data Transfer Object )與資料繫結
[ADO.NET][Winform] DTO 與 DataGridView更新問題

 

2.很簡單,不就下拉選單而已嘛~

3.這應該沒什麼吧!DTO我常在用的,不就資料繫結而已嘛~

不過3.當碰到comboBox + enum 時沒那麼容易的,需要動一點手腳。


 

接著來看看實做過程,以下是我的類別

public enum Zone
{
    Taipei=0,
    Kaohsiung=1,
    Taichung=2,
    Tainan=3
}

public class Member
{
    public Zone Zone { get; set; }
    public string Name { get; set; }
    public string Title { get; set; }
    public int Age { get; set; }
}

用戶端這樣寫:

 

 

BindingSource _source = new BindingSource();
BindingList<Member> _list = null;
private void toolbtnSave_Click(object sender, EventArgs e)
{
    XmlSerialize.SerializeToXml("test.xml", this._source.DataSource);
}

private void Form1_Load(object sender, EventArgs e)
{
    if (!File.Exists("test.xml"))
        this._list = new BindingList<Member>();
    else
        this._list = XmlSerialize.DeserializeFromXml<BindingList<Member>>("test.xml");

    this._source.DataSource = this._list;

    this.bindingNavigator1.BindingSource = this._source;
    this._source.CurrentItemChanged += new EventHandler(_source_CurrentItemChanged);
    //DataSource無資料
    if (this._source.Count == 0)
        isEnableControl(false);

    //資料繫結
    this.txtName.DataBindings.Add("Text", this._source, "Name");
    this.txtTitle.DataBindings.Add("Text", this._source, "Title");
    this.txtAge.DataBindings.Add("Text", this._source, "Age");
    this.cmbZone.DataBindings.Add("Text", this._source, "Zone");

}


void isEnableControl(bool enable)
{
    foreach (Control ctrl in this.Controls)
    {
        if (ctrl is TextBox || ctrl is ComboBox)
        {
            ctrl.Enabled = enable;
        }
    }
}

void _source_CurrentItemChanged(object sender, EventArgs e)
{
    //DataSource有資料
    if (this._source.Count > 0)
    {
        isEnableControl(true);
    }
}

PS.序列化方法若不知道的人請參考  [.NET] 利用 泛型方法 重構 反序列化

PS.txtAge在資料繫結下只接受數字,以及正確的資料型態。

 

 

 


UI長這樣,當我想要改變Zone屬性時卻沒有辦法改,也沒有下拉式選單,問題來了,我沒有辦法變更Zone的屬性,也就是comboBox的內容不會變

image

 

 

先來建立下拉選單,取出enum裡的屬性建立下拉選單

 

 

private void Form1_Load(object sender, EventArgs e)
{
    …略
    createList();
}


void createList()
{
    Array enumValues = Enum.GetValues(typeof(Zone));
    List<string> result = new List<string>();
    for (int i = 0; i < enumValues.Length; i++)
    {
        result.Add(enumValues.GetValue(i).ToString());
    }
    this.cmbZone.DataSource = result;
}

 

為了防止使用者手賤亂Key in資料,我們禁止一切命令輸入(接下來我會用到 TextChanged 事件來處理所以這步驟必須要做)

 

private void Form1_Load(object sender, EventArgs e)
{
    …略
    this.cmbZone.KeyPress += new KeyPressEventHandler(cmbZone_KeyPress);
}


void cmbZone_KeyPress(object sender, KeyPressEventArgs e)
{
    e.Handled = true;
}


這樣一來與使用者互動的機制也建立完成,接下來只剩下寫入comboBox到資料來源了,一直找不到更好的做法,只好硬幹,利用下拉選單的值變更的事件,將資料回填到資料來源;這樣一來在UI上面就可以看到下拉選單的資料也跟著變了。

 

private void Form1_Load(object sender, EventArgs e)
{
    …略
    this.cmbZone.TextChanged += new EventHandler(cmbZone_TextChanged);
}


void cmbZone_TextChanged(object sender, EventArgs e)
{
    ComboBox cmb = (ComboBox)sender;
    string content=cmb.Text;
    if (string.IsNullOrEmpty(content))
        return;
    
    int index = this._source.Position;
    Member member = (Member)this._source[index];
    Zone zone=(Zone)Enum.Parse(typeof(Zone),content);
    member.Zone = zone;
}


後記:

 

在還沒有找到更好的做法以前,只要是無法直接繫結,或是繫結時有問題,我都是這樣硬幹,提供給各位參考,若有更好做法時,也不要吝嗇分享一下唷

 

範例下載:

CmbBoxDatabinding.zip

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


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

Image result for microsoft+mvp+logo