DataGridView的CurrentCell.RowIndex始终为0,如何控制单元格编辑权限
问题根因与解决方案
为什么dgView.CurrentCell.RowIndex取值始终为0
出现该问题有两个核心原因:
CellBeginEdit事件触发时,CurrentCell的选中状态更新逻辑还未完全执行完毕,直接读取该属性会拿到上一次选中的单元格,甚至默认的首行单元格- 原代码在
CellBeginEdit末尾强制调用了.EndEdit(),会直接中断当前编辑流程,打乱DataGridView内部状态更新逻辑,导致行号始终停留在初始值0
编辑规则实现方案
你不需要额外监听鼠标事件,仅通过CellBeginEdit做权限校验、CellEndEdit做数据合法性校验,搭配独立的保存按钮即可满足需求,核心优化点如下:
- 所有事件内优先用参数自带的
e.RowIndex、e.ColumnIndex获取当前编辑的行列位置,精度远高于读取CurrentCell - 不符合编辑权限的场景直接设置
e.Cancel = True即可禁止编辑,无需手动终止编辑流程 - 将数据库更新逻辑从
CellEndEdit移到独立的保存按钮中,避免编辑即入库,符合用户确认后再提交的需求
修正后代码
' 模块级变量存储编辑前的原始值 Private originalValue As Object Private Sub dgTools_CellBeginEdit(sender As Object, e As DataGridViewCellCancelEventArgs) Handles dgTools.CellBeginEdit With dgTools Dim isNewRow As Boolean = (e.RowIndex = .NewRowIndex) ' 仅放行符合编辑规则的场景:新增行第1列、非新增行第4列 If (e.ColumnIndex = 1 AndAlso isNewRow) OrElse (e.ColumnIndex = 4 AndAlso Not isNewRow) Then ' 存储第4列原始值用于后续校验 If e.ColumnIndex = 4 Then originalValue = .Rows(e.RowIndex).Cells(e.ColumnIndex).Value End If Exit Sub End If ' 其余场景全部禁止编辑 e.Cancel = True MsgBox("当前单元格不允许编辑", MsgBoxStyle.Critical, "编辑错误") End With End Sub Private Sub dgTools_CellEndEdit(sender As Object, e As DataGridViewCellEventArgs) Handles dgTools.CellEndEdit Dim dtCheck As DataTable = Nothing Dim hdr As String, msg As String With dgTools ' 仅处理新增行第1列的合法性校验 If e.ColumnIndex = 1 Then Dim currentCell = .Rows(e.RowIndex).Cells(e.ColumnIndex) currentCell.Value = UCase(currentCell.Value?.ToString()) dtCheck = GetDataTable("GetTool_x_BrochsteinsID", "@BrochsteinsID", currentCell.Value) ' 校验ID是否存在 If dtCheck Is Nothing OrElse dtCheck.Rows.Count = 0 Then hdr = "无效的Brochsteins ID" msg = "输入的ID不存在,请输入有效ID" MsgBox(msg, MsgBoxStyle.Critical, hdr) .Rows.RemoveAt(e.RowIndex) GoTo Cleanup End If ' 校验ID是否已被分配 If CInt(dtCheck.Rows(0)("Toolstatus")) > 1 Then hdr = "Brochsteins ID分配非法" msg = $"{dtCheck.Rows(0)("BrochsteinsID")} 已被分配给 {dtCheck.Rows(0)("ToolboxDesc")},请输入其他ID或先将该ID归还工具室" MsgBox(msg, MsgBoxStyle.Critical, hdr) .Rows.RemoveAt(e.RowIndex) GoTo Cleanup End If ' 自动填充其他列信息 With .Rows(e.RowIndex) .Cells(0).Value = dtCheck.Rows(0)("ToolId") .Cells(2).Value = dtCheck.Rows(0)("ModelDesc").ToString() .Cells(3).Value = dtCheck.Rows(0)("CategoryDesc").ToString() .Cells(4).Value = dtCheck.Rows(0)("AssignedNote").ToString() End With End If Cleanup: If dtCheck IsNot Nothing Then dtCheck.Dispose() End With End Sub ' 新增保存按钮点击事件,确认后再批量提交到数据库 Private Sub btnSave_Click(sender As Object, e As EventArgs) Handles btnSave.Click ' 先提交所有未保存的编辑 If dgTools.IsCurrentCellDirty Then dgTools.CommitEdit(DataGridViewDataErrorContexts.Commit) End If ' 遍历所有非新增行执行更新 For Each row As DataGridViewRow In dgTools.Rows If row.IsNewRow Then Continue For Dim toolId = row.Cells("ToolID").Value If toolId Is Nothing OrElse IsDBNull(toolId) Then Continue For Dim note = If(IsDBNull(row.Cells("AssignedNote").Value), "", row.Cells("AssignedNote").Value.ToString()) UpdateTool_Toolbox(toolId, cboToolbox.SelectedValue, note) Next ' 刷新列表 QueryTable("Tools") QueryTable("Standard") MsgBox("数据保存成功", MsgBoxStyle.Information, "提示") End Sub
内容的提问来源于stack exchange,提问作者John Schmalz
相关产品推荐
相关产品推荐

