1:用2个列表对像来分别管理后台和可视数据,方便用户过滤查看数据

    Public mConfigList As DBList(Of ETConfigModbusExport)
    ''' <summary>
    ''' 当前显示的仪表地址列表
    ''' </summary>
    ''' <remarks></remarks>
    Public mCurrentViewList As DBList(Of ETConfigModbusExport)

2:然后在CellValuePushed事件中,获取用户的编辑值

 Private Sub DataGridViewX1_CellValuePushed(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DataGridViewCellValueEventArgs) Handles xDataGridView.CellValuePushed
        If (mHalt) Then
            Return
        End If
        If (e.RowIndex < 0 OrElse e.RowIndex >= mCurrentViewList.Count) Then
            Return
        End If
        With mCurrentViewList(e.RowIndex)
            Try
                .beginEdit(False)
                Select Case e.ColumnIndex
                    Case xColumnRemark.Index
                        .fRemark = e.Value
                    Case xColumnUnitAdjust.Index
                        .fUnitAdjust = e.Value
                    Case xColumnValueAddress.Index
                        .fValueAddress = e.Value
                End Select
            Catch exp As Exception
                MyHub.mBase.mDebugLog.writerError(Me, exp)
            Finally
                .fModifyUser = MyHub.mBase.mUserName
                .fModifyTime = DateTime.Now
                .endEdit(True)
            End Try
        End With


        checkControl()
    End Sub

3:使用CellValueNeeded事件来显示合适的数据

 ''' <summary>
    ''' 读取数据
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub DataGridViewX1_CellValueNeeded(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DataGridViewCellValueEventArgs) Handles xDataGridView.CellValueNeeded
        If (mHalt) Then
            Return
        End If
        If (e.RowIndex < 0 OrElse e.RowIndex >= mCurrentViewList.Count) Then
            Return
        End If
        With mCurrentViewList
            Select Case e.ColumnIndex
                Case xColumnMin.Index
                    e.Value = .Item(e.RowIndex).fMin
                Case xColumnMax.Index
                    e.Value = .Item(e.RowIndex).fMax
                Case xColumnRemark.Index
                    e.Value = .Item(e.RowIndex).fRemark
                Case xColumnUnitAdjust.Index
                    e.Value = .Item(e.RowIndex).fUnitAdjust
                Case xColumnValueAddress.Index
                    e.Value = .Item(e.RowIndex).fValueAddress
            End Select
        End With


    End Sub

4:使用NewRowNeeded事件来赋值合适的初始值,尽量赋给所有的初始值

 Private Sub DataGridViewX1_NewRowNeeded(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DataGridViewRowEventArgs) Handles xDataGridView.NewRowNeeded
        '在数据表中增加一行
        '从当前已有表格中复制


        Dim pClone As ETConfigModbusExport
        Dim pData As ETConfigModbusExport
        If (mCurrentViewList Is Nothing) Then      
            Return
        End If


        If (mCurrentViewList.Count > 0) Then
            pClone = mCurrentViewList(mCurrentViewList.Count - 1)
            pData = pClone.Clone()
            With pData
                .fFieldName = _fieldList(0).mValue
                .fDataType = _DataTypeBindList(0).theValue
                .fRemark = ""
                pData.fValueAddress = addAddressByType(pData.fValueAddress, .fDataType)
            End With
        Else
            pData = New ETConfigModbusExport
            With pData
                .fModuleType = ExtendModuleEnum.tankMonitorFacade
                .fModifyUser = MyHub.mBase.mUserName
                .fObjectType = Me.mObjectType
                .fPrecision = 1.0
                .fOffset = 0
                .fMin = Convert.ToDouble(Int16.MinValue)
                .fMax = Convert.ToDouble(Int16.MaxValue)
                .fRemark = ""
                .fUnitAdjust = 1.0
                .fValueAddress = 1
            End With
        End If
        pData.fGID = Guid.NewGuid()
        mCurrentViewList.Add(pData)
        checkControl()
    End Sub

5:使用RowValidating事件,来检查输入值

Private Sub xDataGridView_RowValidating(sender As System.Object, e As System.Windows.Forms.DataGridViewCellCancelEventArgs) Handles xDataGridView.RowValidating
        If (e.RowIndex < 0 OrElse e.RowIndex >= mCurrentViewList.Count) Then
            Return
        End If
        If (xDataGridView.Visible = False) Then     
            Return
        End If
        Dim pConfig As ETConfigModbusExport = mCurrentViewList(e.RowIndex)
        With pConfig
            ''对于正常数据的显示,如果使用e.Cancel来取消,则会提示”由于程序无法提交或取消单元格值更改,操作失败“,所以正常数据显示不需要验证
            If (.mRowState = DataRowState.Detached OrElse .mRowState = DataRowState.Unchanged OrElse .mRowState = DataRowState.Deleted) Then
                Return
            End If
            If (xDataGridView.IsCurrentRowDirty = False) Then           '如果当前行,没有编辑,则不处理
                Return
            End If
            If (String.IsNullOrEmpty(.fFieldName)) Then         '如果没有选择字段,则直接退出
                MsgBox("请选择输出的数据项", MsgBoxStyle.OkOnly, MyHub.mBase.appTitle)
                e.Cancel = True
                Return
            End If
            If (mConfigList.Exists(Function(p) p.fModbusFunction = .fModbusFunction AndAlso p.fValueAddress = .fValueAddress AndAlso p.fGID <> .fGID)) Then
                MsgBox("配置的地址位已被占用,不能使用此地址", MsgBoxStyle.OkOnly, MyHub.mBase.appTitle)
                e.Cancel = True
                Return
            End If
        End With
    End Sub

6:使用RowValidated事件,把验证成功的数据添加到后台数据列表

 Private Sub xDataGridView_RowValidated(sender As System.Object, e As System.Windows.Forms.DataGridViewCellEventArgs) Handles xDataGridView.RowValidated
        If (e.RowIndex < 0 OrElse e.RowIndex >= mCurrentViewList.Count) Then
            Return
        End If
        If (xDataGridView.Visible = False) Then     '如果表格隐藏,则表明处于初始化或者不需要验证的时候
            Return
        End If
        Dim pConfig As ETConfigModbusExport = mCurrentViewList(e.RowIndex)
        With pConfig
            If (pConfig.mRowState = DataRowState.Detached OrElse .mRowState = DataRowState.Unchanged OrElse .mRowState = DataRowState.Deleted) Then         '如果未经过编辑,则不添加到主界面
                Return
            End If
            If (Me.mConfigList.Contains(pConfig) = False) Then
                Me.mConfigList.Add(pConfig)
            End If
        End With
    End Sub

7:使用CellEndEdit或者CellBeginEdit事件,来联动同一行的上下文数据

    Private Sub xDataGridView_CellEndEdit(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles xDataGridView.CellEndEdit
        If (e.ColumnIndex = Me.xColumnModbusField.Index) Then
            Try
                Dim pValue As String = CType(xDataGridView.Rows(e.RowIndex).Cells(e.ColumnIndex).Value, String)
                If (pValue IsNot Nothing AndAlso _propertyDict.ContainsKey(pValue)) Then
                    bindRowModbusDataType(e.RowIndex, _propertyDict(pValue))
                End If
            Catch ex As Exception
                Return
            End Try
        End If
        If (e.ColumnIndex = Me.xColumnDataType.Index) Then
            '如果选择了字段类型以后,就要根据选择的字段类型,自动计算出后面的数据位,Int16和UInt16增加1,Int32和UInt32增加2位
            autoValueAddress(e.RowIndex)
        End If
    End Sub

8:使用RowEnter判断当前行,并用其他相关事件来检查用户的操作情况

    Private Sub xDataGridView_ReadOnlyChanged(sender As System.Object, e As System.EventArgs) Handles xDataGridView.ReadOnlyChanged
        checkControl()
    End Sub


    Private _CurrentRowIndex As Integer = -1


    Private Sub xDataGridView_RowEnter(sender As System.Object, e As System.Windows.Forms.DataGridViewCellEventArgs) Handles xDataGridView.RowEnter
        _CurrentRowIndex = e.RowIndex
        checkControl()
    End Sub

9:可考虑使用CellFormatting和CellValidating事件对值进行显示格式控制和数据有效性进行检查

    Private Sub xDataGridView_CellFormatting(sender As Object, e As System.Windows.Forms.DataGridViewCellFormattingEventArgs) Handles xDataGridView.CellFormatting
        If (e.ColumnIndex = xMinColumn.Index OrElse e.ColumnIndex = xSafeMinColumn.Index OrElse e.ColumnIndex = xSafeMaxColumn.Index OrElse e.ColumnIndex = xMaxColumn.Index) Then
            If (e.RowIndex >= 0 AndAlso e.RowIndex < mCurrentViewList.Count) Then
                Dim pKeyName As String = mCurrentViewList(e.RowIndex).fKey
                e.CellStyle.Format = MyHub.mModuleMain.mUnitManager.getCurrentDisplayFormat(getFieldUnitClass(pKeyName))
            End If
        End If
    End Sub


    Private Sub xDataGridView_CellValidating(sender As Object, e As System.Windows.Forms.DataGridViewCellValidatingEventArgs) Handles xDataGridView.CellValidating
        If (e.ColumnIndex = xMinColumn.Index OrElse e.ColumnIndex = xSafeMinColumn.Index OrElse e.ColumnIndex = xSafeMaxColumn.Index OrElse e.ColumnIndex = xMaxColumn.Index) Then
            If (Not IsNumeric(e.FormattedValue)) Then
                e.Cancel = True
                xHelp.Text = "请输入有效的数值!"
                MsgBox(xHelp.Text, MsgBoxStyle.OkOnly, MyHub.mBase.appTitle)
            End If
        End If
        checkControl()
    End Sub

10:在窗体关闭前,要检查是否需要保存
    Private Sub FMRangeAndOverTime_FormClosing(sender As Object, e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
        If (Me.xDataGridView.IsCurrentRowDirty()) Then
            Me.xDataGridView.EndEdit()
            Me.xSave.Focus()
        End If
        If (Me.mConfigList.submitRequird) Then
            If (MsgBox("数据未保存,是否退出?", MsgBoxStyle.YesNo, My.Application.Info.Title) = MsgBoxResult.No) Then 
                e.Cancel = True
            End If
        End If
    End Sub