Mô tả lỗi
Bộ phận kiểm thử của công ty phát hiện một lỗi: khi người dùng click vào bảng dữ liệu để mở form đơn hàng, ứng dụng báo lỗi chuyển đổi từ DBNull sang Integer. Vị trí lỗi rất rõ ràng - code đọc giá trị từ DataGridView.CurrentRow.Cells("MID").Value và gán cho biến Integer thì bị ném ngoại lệ. Ban đầu tôi nghĩ là do dữ liệu, nhưng kiểm tra database thì field này không có NULL, và lỗi cũng không xuất hiện luôn khiến việc debug trở nên khó khăn.
Quá trình tái hiện lỗi
Sau nhiều lần debug, tôi phát hiện một hiện tượng rất kỳ lạ: sau khi double-click vào dòng trong bảng nhưng trước khi form đơn hàng thực sự được tải xong, dòng được chọn trong DataGridView lại thay đổi theo vị trí cuối cùng của con trỏ chuột. Nghĩa là: tôi double-click vào một dòng dữ liệu hợp lệ, nhưng khi code đọc CurrentRow thì nó đã trôi sang dòng trống mặc định cuối cùng của DataGridView. Giá trị trong các ô của dòng này tất nhiên là DBNull, và đó chính là nguyên nhân gây ra ngoại lệ.
Phương pháp排查 và giải pháp
If blnInputInfo = False Then
blnInputInfo = True
g_frmInputInfo = New frmInputInfo
g_frmInputInfo.MdiParent = g_frmMain
g_frmInputInfo.Show()
End If
ShowChildform(g_frmInputInfo)
If (currentDgv.Name = "dgvDetail") Then
g_frmInputInfo.clsAll()
g_frmInputInfo.intMID = Me.dgvDetail.CurrentRow.Cells("MID").Value
g_frmInputInfo.txtID.Text = Me.dgvDetail.CurrentRow.Cells("制作单号").Value
g_frmInputInfo.readInfo()
ElseIf currentDgv.Name = "dgvRedoDetail" Then
g_frmInputInfo.clsAll()
g_frmInputInfo.intMID = Me.dgvRedoDetail.CurrentRow.Cells("MID").Value
g_frmInputInfo.txtID.Text = Me.dgvRedoDetail.CurrentRow.Cells("制作单号").Value
g_frmInputInfo.readInfo()
End If
Trong quá trình tải form này, các tác vụ tốn thời gian không được đặt trong phương thức bất đồng bộ. Lý duy giao diện vẫn phản hồi được với thiết bị ngoại vi là thao tác chuột tiếp tục được đưa vào vòng lặp tin nhắn Windows. Trong WinForms, tôi có thể nghĩ đến một phương thức liên quan là Application.DoEvents(). Quả nhiên trong sự kiện tải form g_frmInputInfo, tôi tìm thấy rất nhiều lời gọi Application.DoEvents(). Tuy nhiên, nếu xóa bỏ chúng tùy tiện, sẽ không biết chắc có gây ra vấn đề khác không. Cuối cùng hỏi AI, và giải pháp được đưa ra là tắt DataGridView trước khi tải form rồi bật lại sau khi hoàn tất - và nó đã hoạt động.
' Tắt DataGridView trước khi tải form
currentDgv.Enabled = False
If blnInputInfo = False Then
blnInputInfo = True
g_frmInputInfo = New frmInputInfo
g_frmInputInfo.MdiParent = g_frmMain
g_frmInputInfo.Show()
End If
ShowChildform(g_frmInputInfo)
currentDgv.Enabled = True
If (currentDgv.Name = "dgvDetail") Then
g_frmInputInfo.clsAll()
g_frmInputInfo.intMID = Me.dgvDetail.CurrentRow.Cells("MID").Value
g_frmInputInfo.txtID.Text = Me.dgvDetail.CurrentRow.Cells("制作单号").Value
g_frmInputInfo.readInfo()
ElseIf currentDgv.Name = "dgvRedoDetail" Then
g_frmInputInfo.clsAll()
g_frmInputInfo.intMID = Me.dgvRedoDetail.CurrentRow.Cells("MID").Value
g_frmInputInfo.txtID.Text = Me.dgvRedoDetail.CurrentRow.Cells("制作单号").Value
g_frmInputInfo.readInfo()
End If