摘要:使用泛型類別解決 ComboBox 的自訂資料繫結問題
為了要在 ComboBox 的第一個項目加入一個空白項目,例如:「請選擇」,又不想在資料庫裡面加入這個空白項目,因此只好放棄原本的資料繫結功能(即 DataSource, DisplayMember, 和 ValueMember),而得改用其他方法(姑且稱之為自訂資料繫結)。試了幾種寫法之後,最後決定用泛型類別。
這篇文章主要就是紀錄這個解決問題的過程和方法。只是標題下得不是很好,不過我也想不出更簡潔又明暸的標題了。
第一次的解決方法,是另外建一個 Hashtable 物件,把 ComboBox 裡面要填入的資料先從 DataSet 中逐一取出並填入 Hashtable 物件。當然,第一項會填入一個空白項目。以下是範例:
Hashtable htbl = new Hashtable(); .... ComboBox1.Items.Clear(); ComboBox1.Items.Add("請選擇"); // 把查閱資料填入 ComboBox 時,順便複製一份 key-value pair 到 Hashtable 中. foreach (DataRow row in DataSet1.Tables[0].Rows) { ComboBox1.Items.Add(row["Name"].ToString()); htbl.Add(row["ID"].ToString(), row["Name"].ToString()); }
等到需要取得使用者在 ComboBox 中選取的項目所對應的 key 值時,就取出ComboBox 目前選取的文字字串,並以該字串到 Hashtable 中搜尋,取出對應的 key 值。
這個做法的缺點是,ComboBox 裡面有一份顯示的文字項目,Hashtable 裡面也保留了一份,顯得有點浪費。如果 ComboBox 裡面儲存的項目就同時包含了 Key 跟 Value,這樣就比較有效率,也不需要另外維護一個 Hashtable 物件。
因此,接下來的目標就是尋找一種可以儲存 key 跟 value 的物件,屆時只要把這個物件加入到 ComboBox 的 Items 集合就行了。本想自己寫一個,類別名稱就叫做 KeyValuePair,但轉念一想:會不會 .NET Framework 已經有提供了?於是到 MSDN Library 搜尋了一下,結果竟然真的有這個型別。原來 .NET Framework 2.0 增加了一個新的泛型結構: KeyValuePair,似乎就是我要的。
既然有現成的,就直接拿來用了,原本的程式碼便改成這樣:
KeyValuePair kvp; ComboBox1.Items.Clear(); kvp = new KeyValuePair<string, string>("", "請選擇"); ComboBox1.Items.Add(kvp); foreach (DataRow row in DataSet1.Tables[0].Rows) { kvp = new KeyValuePair<string, string>(row["ID"].ToString(), row["Name"].ToString()); ComboBox1.Items.Add(kvp); }
看起來不錯,可是實際執行時,ComboBox 裡面顯示的每一個項目,卻是把 key 和 value 同時顯示出來。這是由於 KeyValuePair 的 ToString() 方法會把 key 和 value 都轉成字串,並且把它們串接成一個字串的緣故。
由於 KeyValuePair 是結構,無法繼承,也就無法改寫它的 ToString() 方法。看來只好自己寫一個了,還好也不是很複雜,程式碼如下:
public struct KeyValuePairEx<TKey, TValue> { private TKey mKey; private TValue mValue; public KeyValuePairEx(TKey key, TValue value) { mKey = key; mValue = value; } public TKey Key { get { return mKey; } set { mKey = value; } } public TValue Value { get { return mValue; } set { mValue = value; } } public override string ToString() { return mValue.ToString(); } }
這個自訂的 KeyValuePairEx 結構唯一特別的地方,就是 ToString() 方法只會傳回 value 字串,以便讓 ComboBox 顯示時,只顯示 value,不顯示 key。
把自訂的 KeyValuePairEx 寫好之後,只要把之前的程式碼的 KeyValuePair 替換成 KeyValuePairEx 就行了,因為兩者的用法完全一樣,如下:
KeyValuePairEx kvp; ComboBox1.Items.Clear(); kvp = new KeyValuePairEx<string, string>("", "請選擇"); ComboBox1.Items.Add(kvp); foreach (DataRow row in DataSet1.Tables[0].Rows) { kvp = new KeyValuePairEx<string, string>(row["ID"].ToString(), row["Name"].ToString()); ComboBox1.Items.Add(kvp); }
結語:
解題的方式有很多,也不是一定要用泛型啦,用 object 也可以儲存任何物件,只是需要手動轉型,而且缺乏編譯時期的型別安全檢查。