一 需求介紹
一般像枚舉類型的數據,我們在數據庫里存儲着諸如(1、2、3、4…)或者(“001”、“002”、“003”…)此類,但是界面上我們想要顯示的是具體的文本內容,以便用戶理解使用。所以在從數據庫中加載出來的數據 DataTable 綁定到 DataGridView 上時,就需要其中一些枚舉列采用下拉框,並綁定對應的枚舉數據源。
二 具體實現
首先,如果 DataGridView 的 AutoGenerateColumns 為 true 時,在綁定 DataTable 到 DataGridView 上時,會自動生成綁定數據中的各列,且默認均為普通的 DataGridViewTextBoxColumn 。所以如果要設置 DataGridView 中的下拉列,首先要把 AutoGenerateColumns 設置為 false。
1 /// <summary> 2 /// Sample 3 /// DataGridView綁定DataTable,ComboBox列綁定enum枚舉 4 /// </summary> 5 public MainForm() 6 { 7 InitializeComponent(); 8 9 DataTable dataTable = CreateDataTable(); 10 dataGridView.AutoGenerateColumns = true;// 默認設置 11 dataGridView.DataSource = dataTable; 12 // SetGridView(dataTable); 13 } 14 15 /// <summary> 16 /// 構建數據源 17 /// 可以從數據庫讀取出來構建DataTable數據源 18 /// </summary> 19 /// <returns>DataTable數據表</returns> 20 public DataTable CreateDataTable() 21 { 22 DataTable dt = new DataTable(); 23 dt.Columns.Add(new DataColumn("Id", typeof(int))); 24 dt.Columns.Add(new DataColumn("Name", typeof(string))); 25 dt.Columns.Add(new DataColumn("EnumCol1", typeof(int))); 26 dt.Columns.Add(new DataColumn("EnumCol2", typeof(string))); 27 Random r = new Random(); 28 for (int i = 0; i < 50; i++) 29 { 30 DataRow dr = dt.NewRow(); 31 dr[0] = r.Next(); 32 dr[1] = "Name = " + r.Next(); 33 dr[2] = r.Next(1, 5); 34 dr[3] = "EnumCol_" + r.Next(1, 5); 35 dt.Rows.Add(dr); 36 } 37 38 return dt; 39 }
效果圖(AutoGenerateColumns = true):
在將 AutoGenerateColumns 屬性設置為 false 后,就要手動生成各列了。其中 EnumCol1 列要綁定一個枚舉類型,EnumCol2 要綁定一個字典類型(Dictionary<string, string>)。
1 /// <summary> 2 /// 枚舉1 3 /// </summary> 4 private enum EnumCol1 5 { 6 A = 1, 7 B = 2, 8 C = 3, 9 D = 4, 10 E = 5 11 } 12 /// <summary> 13 /// 枚舉轉字典 14 /// </summary> 15 /// <typeparam name="T"></typeparam> 16 /// <param name="enumType"></param> 17 /// <returns></returns> 18 private Dictionary<int, string> EnumToDictionary(Type enumType) 19 { 20 Dictionary<int, string> result = new Dictionary<int, string>(); 21 foreach (int key in Enum.GetValues(enumType)) 22 { 23 string value = Enum.GetName(enumType, key); 24 result.Add(key, value); 25 } 26 27 return result; 28 }
通過上面的代碼中 EnumToDictionary 方法把枚舉類型轉換為字典類型,這樣就可以統一處理數據綁定了。
1 /// <summary> 2 /// 設置DataGridView視圖 3 /// </summary> 4 /// <param name="dt">數據源表</param> 5 public void SetGridView(DataTable dt) 6 { 7 // 在放棄綁定時自動生成列,並且還未初始化DataGridView的列時 8 // 手動生成各列 9 if (!dataGridView.AutoGenerateColumns && dataGridView.Columns.Count == 0) 10 { 11 Dictionary<int, string> dic = EnumToDictionary(typeof(EnumCol1)); 12 foreach (DataColumn dc in dt.Columns) 13 { 14 string colName = dc.ColumnName; 15 DataGridViewColumn dgvc = null; 16 if (colName.StartsWith("EnumCol"))// 生成下拉列 17 { 18 dgvc = new DataGridViewComboBoxColumn(); 19 BindingSource bs = new BindingSource(); 20 if (colName.EndsWith("1"))// 綁定枚舉1 21 { 22 bs.DataSource = dic; 23 dgvc.ValueType = typeof(int); 24 } 25 else if (colName.EndsWith("2"))// 綁定枚舉2 26 { 27 bs.DataSource = new Dictionary<string, string>() 28 { 29 {"EnumCol_1", "AA"}, 30 {"EnumCol_2", "BB"}, 31 {"EnumCol_3", "CC"}, 32 {"EnumCol_4", "DD"}, 33 {"EnumCol_5", "EE"} 34 }; 35 dgvc.ValueType = typeof(string); 36 } 37 ((DataGridViewComboBoxColumn)dgvc).DisplayMember = "Value"; 38 ((DataGridViewComboBoxColumn)dgvc).ValueMember = "Key"; 39 ((DataGridViewComboBoxColumn)dgvc).DataSource = bs; 40 ((DataGridViewComboBoxColumn)dgvc).DisplayStyle = DataGridViewComboBoxDisplayStyle.Nothing; 41 ((DataGridViewComboBoxColumn)dgvc).FlatStyle = FlatStyle.Flat; 42 } 43 else// 生成普通列 44 { 45 dgvc = new DataGridViewTextBoxColumn(); 46 } 47 dgvc.Name = colName; 48 dgvc.DataPropertyName = colName;// 保證該列的值綁定到DataTable中colName列上 49 dataGridView.Columns.Add(dgvc); 50 } 51 } 52 } 53
在列類型為 DataGridViewComboBoxColumn,且要綁定字典數據源(Dictionary)時,需要通過 BindingSource 。即:
BindingSource bs = new BindingSource();
bs.DataSource = dic;
((DataGridViewComboBoxColumn)dgvc).DataSource = bs;
需要特別注意的是==>
48行代碼:
dgvc.DataPropertyName = colName; 表示該下拉列的值綁定對應於數據源 DataTable 中 colName 列數據;
37行、38行代碼:
((DataGridViewComboBoxColumn)dgvc).DisplayMember = "Value";
((DataGridViewComboBoxColumn)dgvc).ValueMember = "Key";
DisplayMember 是表示下拉框顯示的值綁定於 dgvc 的數據源的某個位置(字典的Value);
ValueMember 是表示下拉框實際值綁定於 dgvc 的數據源的某個位置(字典的Key);
23行、35行代碼:
dgvc.ValueType = typeof(int);
dgvc.ValueType = typeof(string);
這兩句則是指定該列綁定數據源里該列的類型。此時,必須保證數據源 DataTable 里該列的值類型,必須和該列的 ValueMember 屬性綁定的數據源類型一致。以文中例子,即 datagridview 的列 EnumCol1 和列 EnumCol2 的數據類型必須和所綁定的 Dictionary 的 Key 類型一致(因為 dgvc 的 ValueMember 屬性綁定於 Key)。
效果圖:
三 追加幾句
1、SQLite 數據庫中的 INTEGER 和 INT 類型區別需要通過“Tools –> Options –> Type Mappings”來確定。
但是實際上,其中 INT 類型是與C#的 Int32 對應,如果將 INTEGER 類型的列綁定到 Dictionary<int, string>上,是會報如下錯誤的:
2、本文以 DataGridViewComboBoxColumn 列綁定 Dictionary 字典數據源為例說明具體綁定細節,當然該類型列也可以綁定於 DataTable 等其他類型數據,只要設置好綁定細節就可以了。



