You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 07:51:01