DataGridView控件是微軟預先寫好的一個顯示數據的控件,功能非常強大,可以顯示來自數據庫表的數據和XML等其他來源的數據。最近在做一個迷你超市管理系統,要大量用到這個控件。所以花時間好好研究了下。
這是迷你超市管理系的庫存數據DataGridView,用戶一定會想如果能直接在DGV中修改數據就好了。
是的,這是一個很好的想法,這個功能微軟早就幫我們想到了,現在可以使兩種方法加以實現。下面就來介紹一下他們。
第一張方法:基於DataAdapter對象創建一個CommandBulider,用來生成Sql命令,修改數據源,從而直接更改數據表的內容。
前提是:
1.這個表必須有主鍵,否則該對象無法生成Update和delete、insert的Sql命令,報異常:
對於不返回任何鍵列信息的 SelectCommand,不支持 UpdateCommand 的動態 SQL 生成。
2.實例化SqlCommandBuilder對象的數據適配器對象SqlDataAdapter必須預先設置好SelectCommand屬性
3.更新的表中不能包括image類型的字段(列)
由於出錯的情況有很多,程序員無法完全掌握,所以我們強烈建議將更新代碼寫在try catch里
下面是此方法的實例:
/// <summary> /// 數據適配器 /// </summary> SqlDataAdapter adapter = null; /// <summary> /// 數據集對象 /// </summary> DataSet dSet = null; /// <summary> /// 連接字符串 /// </summary> private static string strConn = "server=.\\sqlexpress;database=MySchool;uid=sa;pwd=123456"; /// <summary> /// 窗體加載事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Form3_Load(object sender, EventArgs e) { adapter = new SqlDataAdapter("select * from UserInfo", strConn); dSet = new DataSet(); adapter.Fill(dSet); DGVMain.DataSource = dSet.Tables[0]; } /// <summary> /// 更新按鈕點擊事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button1_Click(object sender, EventArgs e) { //創建命令重建對象 SqlCommandBuilder scb = new SqlCommandBuilder(adapter); //更新數據 try {
//這里是關鍵 adapter.Update(dSet); } catch (SqlException ex) { MessageBox.Show(ex.Message); } }
由於各種原因,性能問題,安全問題和其他復雜的因素。
主要缺點:
1、 基於單表,只能對一個數據源表進行更新,如果要更新數據庫
中的已改變的表,則不能用它來更新了。
2、 要求數據庫中必須設置好主鍵字段
3、 不能對存有圖片的數據庫進行增刪改操作
4、 執行起來,速度相對於非自動化慢(當然,是在數據庫的規模
很大的情況下)
需要注意的地方:
1、 必須與DataAdapter結合使用
2、 實例化SqlCommandBuilder對象前,必須先指定好數據適配器
的填充命令(SelectCommand)。
3、 填充命令(Select 語句)中返回的列要包括主鍵列,否則將無
法產生Update,和Delete語句。
4、 使用命令構建器比手動編寫SQL更好,但是它們只能處理一個
表,底層的數據庫表必須有主鍵或唯一鍵。另外,數據適配器的SelectCommand屬性必須有一個包含主鍵的查詢。
這種方法在實際項目中根本不會用到,一些小項目和初學者可以嘗試。
第二種方法:定位被修改的單元格,獲取列名和id,構建SQL然后,然后執行更新操作。
這種方法比第一張方法復雜多,效果卻是一樣的,一般也不太會去用。這里簡單介紹一下。思路是:點擊單元格觸發DGV的CellBeginEdit事件,在此事件中保存原先的值到成員字段中,然后在DGV的CellEndEdit事件中修改數據,執行更新。
具體的代碼:
#region DGV直接編輯修改數據的功能 /// <summary> /// 用來存放DGV單元格修改之前值 /// </summary> Object cellTempValue = null; /// <summary> /// DGV單元格開始編輯時觸發的事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void DGVMain_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e) { cellTempValue = DGVMain.Rows[e.RowIndex].Cells[e.ColumnIndex].Value; } /// <summary> /// DGV單元格結束編輯時觸發的事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void DGVMain_CellEndEdit(object sender, DataGridViewCellEventArgs e) { //判斷編輯前后的值是否一樣(是否修改了內容) if (Object.Equals(cellTempValue, DGVMain.Rows[e.RowIndex].Cells[e.ColumnIndex].Value)) { //如果沒有修改,則返回 return; } //判斷用戶是否確定修改 if (MessageBox.Show("確定修改?", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.None) != DialogResult.OK) { //如果不修改,恢復原來的值 DGVMain.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = cellTempValue; return; } //修改數據庫的數據 string sql = String.Format("update set {1}='{2}' where 商品編號='{3}'", DGVMain.Columns[0].DataPropertyName, //所選單元格列名 DGVMain.Rows[e.RowIndex].Cells[e.ColumnIndex].Value, //所選單元格修改后的值 DGVMain.Rows[e.RowIndex].Cells[0].Value //所選行的商品編號 ); try { OleDbHelper.ExecuteNonQuery(CommandType.Text, sql); } catch (OleDbException ex) { MessageBox.Show(ex.Message); } //刷新數據 LoadDGV(); } #endregion
個人建議的解決方案:做一個ContextMenu菜單,綁定DGV,菜單中有修改數據和刪除數據,當用戶選擇整行后,點擊右鍵選擇修改信息,立即彈出一個窗口,根據該行的id重新從數據庫中取出該行記錄的所有值,賦值到各個文本框中,然后點擊更新,執行更新操作。這是最最純潔的方法。