[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的內容不會變
先來建立下拉選單,取出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;
}
後記:
在還沒有找到更好的做法以前,只要是無法直接繫結,或是繫結時有問題,我都是這樣硬幹,提供給各位參考,若有更好做法時,也不要吝嗇分享一下唷
範例下載:
若有謬誤,煩請告知,新手發帖請多包涵
Microsoft MVP Award 2010~2017 C# 第四季
Microsoft MVP Award 2018~2022 .NET