【C#】避免 DataGridView 排序導致取錯行:請用 DataBoundItem 而非 Rows[e.RowIndex]

| CSharp | 1 Reads

在使用 WinForms 的 DataGridView 搭配 DataTable 或其他繫結資料來源時,你是否曾遇過以下狀況?

使用者編輯某一列的資料,但實際讀取或更新的卻是另一筆記錄?

這種問題多半發生在你直接用 dgv.Rows[e.RowIndex] 存取儲存格資料,而此時 DataGridView 剛好啟用了排序或過濾功能。本文將說明這個問題的成因,並提供正確的寫法。


❌ 錯誤寫法:Rows[e.RowIndex]

我們常見的寫法如下:

object keyValue = dgv.Rows[e.RowIndex].Cells[meta.KeyColumn].Value;

這段程式碼看似沒問題,但如果你的 DataGridView 是透過 DataSource 綁定了 DataTable,一旦啟用了排序(點擊欄位標題排序)或過濾功能,那麼 Rows[e.RowIndex] 的行就不再對應於 DataTable 中的原始資料順序

換句話說,你以為你正在取用第 N 筆資料,但實際上拿到的可能是另一筆。


✅ 正確寫法:使用 DataBoundItem

解法其實很簡單:繞過 DataGridView 的顯示順序,直接存取資料來源本體

var row = ((DataRowView)dgv.Rows[e.RowIndex].DataBoundItem).Row;
object keyValue = row[meta.KeyColumn];

這段寫法中,我們透過 DataBoundItem 取得資料列的 DataRowView,再從中拿到真實的 DataRow。這樣可以確保你抓到的資料始終是原始資料來源中的正確一筆,無論使用者如何排序或篩選畫面。


🧪 測試方式建議

  1. DataGridView 綁定一個 DataTable

  2. 啟用 AllowUserToOrderColumns = true

  3. 實作 CellValueChangedCellEndEdit

  4. 測試排序前後,所取得的 row["主鍵"] 是否仍一致。


📝 小結

寫法 是否正確 說明
dgv.Rows[e.RowIndex].Cells[...] ❌ 錯誤 容易因排序導致取錯行
((DataRowView)dgv.Rows[e.RowIndex].DataBoundItem).Row ✅ 正確 可準確取得原始資料行

在 WinForms 資料繫結的世界裡,DataBoundItem 是你和資料來源間的「真實通道」。別再依賴 DataGridView 排序後的表面行順序,否則 debug 時你可能會陷入一場無止盡的謎團。

This article was last edited at