一、上午《01、修改dgv控件中下拉列表的添加》--《03、添加了ValueMenber之后列綁定屬性的修改》
1、將DataGridView中的列指定為需要的類型。
如下圖:創建DataGridViewColumn時需要指定為真正需要的子類型。這樣才能更好地編輯行數據。這些類型有:Button、CheckBox、ComboBox、Image、Link、TextBox
這些子類型的列,正如其名。與同名的單獨控件有類似的屬性、功能和事件。比如DataGridViewButtonColumn就像一個Button控件;而DataGridViewComboBoxColumn就像一個ComboBox控件,可以綁定下拉列表的數據源,可以指定項應該顯示綁定對象的什么屬性,選中值應該對應綁定對象的什么屬性。等等。
2、指定下拉項的數據源。
如以下代碼:
1 //在DataGridView表格控件綁定數據源之前,先綁定下拉列表列的數據源。如此一來,用戶編輯該列時,可以下拉選擇可選項。 2 var column = this.dgvList.Columns["cname"] as DataGridViewComboBoxColumn;//注意:表格列名 = 數據庫列名 = 實體類屬性名。推薦這樣的命名方式。必須將列顯式轉為子類型。 3 if (column != null) 4 { 5 column.DisplayMember = "cname"; //顯示值。即綁定實體對象的屬性名。 6 column.ValueMember = "cid";//實際值 有更高的優先級,如果同時指定了這兩項屬性,那么真正的對應字段是ValueMember.以后拿出來進行匹配的就是cid值。與之匹配的也必須是對應類型和意義的字段或者屬性名稱 7 column.DataSource = cm.GetAllClassesList(false);//BLL層通過DAL層獲取實體對象集合——“班級表”的查詢結果集 8 column.DisplayStyle = DataGridViewComboBoxDisplayStyle.Nothing;//非編輯時,不顯示下拉按鈕 9 } 10 11 this.dgvList.DataSource = pm.GetAllPersonList(false);//DataGridView綁定數據源(BLL層從DAL層獲取的實體對象集合)
注意:ValueMember指定屬性的數據類型必須與該列的綁定數據源屬性的數據類型一致。
針對上例來說:ValueMember指定的是Classes實體類的CID屬性。該DataGridViewComboBoxColumn列綁定的是Person實體類的PCID屬性。(這兩個屬性就是主外鍵關系,Person表的外鍵PCID對應Classes表的主鍵CID)。所以:Classes實體類的CID屬性和Person實體類的PCID屬性都是int整型。這個必須要一致。
3、下拉列異常分析
當彈出下圖異常時,要冷靜分析,該異常說明了這樣幾個問題:
(1)從哪個單元格開始沒加載,說明哪筆數據綁定到表格控件時出了問題。(紅圈處)
(2)“所在班級”列的下拉列表中不存在紅圈內的項。
(3)觀察數據源可知,Person表ID為39的記錄其PCID值為64(PCID是外鍵,指向Classes表的CID),而從Classes班級表獲取的結果集中,不存在CID為64的記錄。(可能是某些歷史原因)
表中數據如下:
4、DataGridView其他注意事項
(1)每次綁定DataGridView.DataSource數據源的時候,都會觸發SelectionChanged事件。
也就是說如果你訂閱了SelectionChanged事件,每次對DataSource賦值后,下一句馬上就去執行該事件處理的代碼。當這個事件處理方法結束,才會接着執行賦值語句下一行。流程如下圖所示:
因為DataGridView控件的SelectionMode有5個類型,分別代表選中模式(單元格選中、整行選中、整列選中、點單元格只選單元格點行頭選中整行、點單元格只選單元格點列頭選中整列)詳見上右圖。所以如果你訂閱了SelectionChanged事件,每次對DataSource賦值后,都會進入5次SelectionChanged事件處理方法。
(2)手動讓單元格進入編輯狀態
允許用戶編輯單元格時,默認情況下用戶需要先選擇行(或單元格),再雙擊單元格才能開始編輯(我試了試開始編譯一個未選中的單元格需要點擊3次鼠標左鍵)。有的人喜歡選中單元格時直接進入編輯狀態。可以使用如下代碼,手動進入編輯狀態。
1 //點擊單元格,指定立馬進入該單元格的編輯狀態 2 private void dgvList_CellClick(object sender, DataGridViewCellEventArgs e) 3 {//點擊單元格,指定進入到編輯狀態 4 this.dgvList.BeginEdit(true); 5 }
注意:但是這樣做也有不爽的地方,有的人閱讀內容的時候喜歡在字里行間點來點去,一不小心修改了內容並換了行。那就直接Update了。
二、上午《04、添加切換行和判斷是否進入編輯狀態的事件》--《07完成直接在dgv控件中進行的修改操作》 --直接在DataGridView的行上修改數據后Update到數據庫
1、訂閱DataGridView的CellBeginEdit和SelectionChanged事件,實現行數據修改后Update到數據庫的功能。
1 //下面字段用於標識單元格編輯后,只有在數據被改變才Update數據庫。 2 private bool _isEdited = false;//選中行是否進入過編輯狀態 3 private bool _isFirst = true;//單元格是不是該行第一個進入修改的單元格。顯而易見一行可以有多個單元格被編輯,每個單元格被編輯都會進入CellBeginEdit事件處理。 4 private Person _current;//選中行綁定項 5 private Person _original = new Person();//編輯前的實體對象(用來在用戶選中其他行后,把編輯前和現在綁定的對象數據做對比,只有真正修改了才去Update數據庫) 6 7 private void dataGridView1_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e) 8 {//選中單元格進入編輯狀態時觸發。(主要用來保存編輯前的數據) 9 _isEdited = true; 10 _current = this.dataGridView1.CurrentRow.DataBoundItem as Person;//這是編輯前。_current就是選中行綁定項 11 if (_isFirst) 12 {//如果本單元格是該行第一個進入編輯的,應該把_current存到_original中,也就是把編輯前對象存好。而編輯后_current的內容會隨之改變。 13 _original.PCID = _current.PCID; 14 _original.PCName = _current.PCName; 15 _original.PGender = _current.PGender; 16 _original.PEmail = _current.PEmail; 17 _original.PType = _current.PType; 18 _isFirst = false; 19 } 20 } 21 22 private void dataGridView1_SelectionChanged(object sender, EventArgs e) 23 {//當用戶選中另一行之后,如果剛才編輯的行數據修改了,應該Update數據庫。 24 if (_isEdited)//如果上一個選中行被編輯過(進過編輯狀態) 25 { 26 if (_original.PCID != _current.PCID || _original.PCName != _current.PCName || _original.PGender != _current.PGender 27 || _original.PType != _current.PType || _original.PEmail != _current.PEmail) 28 {//如果上一個選中行綁定的數據做了編輯修改 29 30 if (UpdatePerson(_current) == 1) 31 {//Update實體對象到數據庫 32 MessageBox.Show("ok"); 33 _isEdited = false; 34 this.dataGridView1.DataSource = GetList(); 35 } 36 } 37 _isFirst = true; 38 _isEdited = false; 39 } 40 }
注意:每個時間點上,獲取的this.dataGridView1.CurrentRow.DataBoundItem綁定項,都是綁定的實時的數據(實體對象)。
也就是說每次改動了綁定項的數據,下次再獲取該綁定項,獲取的就是每次修改后的實體對象。