DataGridView实用的虚拟模式应用示例
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