https://blog.csdn.net/update7/article/details/80066231
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重新從數據庫中取出該行記錄的所有值,賦值到各個文本框中,然后點擊更新,執行更新操作。這是最最純潔的方法。

