VB.NET中同一表单兼作查看/插入时DataGridView CellValidated事件报错
问题:VB.NET同一表单实现发票查看/录入时CellValidated事件报错
我尝试用同一个Frm_Invoice表单同时实现发票明细查看和发票录入功能,但在查看模式下点击DataGridView的ProductName列时,CellValidated事件触发报错。请问能否在查看模式下禁用该事件?我的代码是否存在问题?请给予指导。
invoicepage代码
Imports System.ComponentModel Imports System.Data.OleDb Imports System.Reflection Imports Dapper Public Class invoicepage Dim InvoicesService As New InvoicesService() Private bindingSource As BindingSource = Nothing Public Sub New() ' This call is required by the designer. InitializeComponent() ' Add any initialization after the InitializeComponent() call. ' To reduce the flickering... DataGridView1.GetType(). GetProperty("DoubleBuffered", BindingFlags.Instance Or BindingFlags.NonPublic). SetValue(DataGridView1, True) DataGridView1.ReadOnly = True LoadData() DataGridView1.Columns.Add(New DataGridViewLinkColumn With { .Name = "Colview", .Text = "👁🗨", .HeaderText = "", .DisplayIndex = 1, .UseColumnTextForLinkValue = True, .ActiveLinkColor = System.Drawing.Color.MediumAquamarine, .LinkColor = System.Drawing.Color.MediumAquamarine, .VisitedLinkColor = System.Drawing.Color.MediumAquamarine, .LinkBehavior = LinkBehavior.NeverUnderline, .ReadOnly = True, .DataPropertyName = "Colview"}) End Sub Private Sub LoadData() Dim list = InvoicesService.GetInvoices() bindingSource = New BindingSource With {.DataSource = New BindingList(Of Invoices)(CType(InvoicesService.GetInvoices(), IList(Of Invoices)))} DataGridView1.DataSource = bindingSource DataGridView1.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells) End Sub Private Function GetSELECT() As Invoices Return If(DataGridView1.SelectedCells.Count = 0, Nothing, TryCast(DataGridView1.SelectedCells(0).OwningRow.DataBoundItem, Invoices)) End Function Private Sub DataGridView1_CellContentClick(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView1.CellContentClick Dim dgv = DirectCast(sender, DataGridView) If e.RowIndex >= 0 AndAlso dgv.Columns(e.ColumnIndex) Is DataGridView1.Columns("colview") Then Dim SelectDgv = GetSELECT() Dim frm = New Frm_Invoice(SelectDgv) If (TryCast(Application.OpenForms("Frm_Invoice"), Frm_Invoice)) IsNot Nothing Then 'Form is already open MessageBox.Show("Form is already open") Else ' Form is not open 'MessageBox.Show("Form is not open") frm.Show() End If End If End Sub End Class
Frm_Invoice(交易表单)代码
Imports System.ComponentModel Imports System.Data.OleDb Imports System.Reflection Imports Dapper Public Class Frm_Invoice Inherits Form Private dictProducts As Dictionary(Of String, ProductFinaltesting) Private BindingSource1 As BindingSource = Nothing Private BindingSource2 As BindingSource = Nothing Dim InvoicesService As New InvoicesService() Public Sub New(Invno As Invoices) Me.New ' To reduce the flickering... DataGridView1.GetType(). GetProperty("DoubleBuffered", BindingFlags.Instance Or BindingFlags.NonPublic). SetValue(DataGridView1, True) DataGridView1.AllowUserToAddRows = False BindingSource1 = New BindingSource With {.DataSource = New BindingList(Of InvoicesDetail)(CType(InvoicesService.GetInvoicesdetail(Invno.INVNO), IList(Of InvoicesDetail)))} DataGridView1.DataSource = BindingSource1 DataGridView1.ReadOnly = True TextBox1.Text = Invno.INVNO End Sub Public Sub New() ' This call is required by the designer. InitializeComponent() ' To reduce the flickering... DataGridView1.GetType(). GetProperty("DoubleBuffered", BindingFlags.Instance Or BindingFlags.NonPublic). SetValue(DataGridView1, True) updateDataSource() End Sub Protected Overrides Sub OnLoad(e As EventArgs) MyBase.OnLoad(e) End Sub Protected Sub updateDataSource() dictProducts = ProductFinaltestingService.GetDistinctProducts(). ToDictionary(Function(p) p.ToString(), Function(p) p) BindingSource1 = New BindingSource With {.DataSource = New BindingList(Of ProductFinaltesting)} DataGridView1.AutoGenerateColumns = False DataGridView1.AllowUserToAddRows = False DataGridView1.DataSource = BindingSource1 DataGridView1.Columns("Unit").ReadOnly = True DataGridView1.Columns("No").ReadOnly = True DataGridView1.Columns("Prp").ReadOnly = True DataGridView1.Columns("Prs").ReadOnly = True BindingSource1.AddNew() DataGridView1.Select() End Sub Private Sub DataGridView1_CellValidated( sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView1.CellValidated Dim dgv = DirectCast(sender, DataGridView) If e.ColumnIndex = dgv.Columns("ProductName").Index Then Dim p As ProductFinaltesting = Nothing Dim key = dgv(e.ColumnIndex, e.RowIndex).Value?.ToString().Trim() If key Is Nothing Then Return If dictProducts.TryGetValue(key, p) Then Dim boundItem = TryCast(dgv.Rows(e.RowIndex).DataBoundItem, ProductFinaltesting) 'Error below line code If p.Unit <> boundItem.Unit Or p.Prp <> boundItem.Prp Or p.Prs <> boundItem.Prs Then boundItem.Unit = p.Unit dgv.UpdateCellValue(dgv.Columns("Unit").Index, e.RowIndex) boundItem.Prp = p.Prp dgv.UpdateCellValue(dgv.Columns("Prp").Index, e.RowIndex) boundItem.Prs = p.Prs dgv.UpdateCellValue(dgv.Columns("Prs").Index, e.RowIndex) End If dgv.Rows(e.RowIndex).ErrorText = Nothing Btnsave.Visible = True End If End If End Sub End Class

问题原因与解决方法
核心问题
报错的本质是:
- 查看模式下DataGridView绑定的是
InvoicesDetail类型数据,但CellValidated事件里强行将其转换为ProductFinaltesting类型,类型不匹配导致空引用异常。 - 即使设置了DataGridView为ReadOnly,单元格获得/失去焦点时仍会触发CellValidated事件。
解决方案
1. 添加模式标识字段
在Frm_Invoice类中新增私有字段标记当前模式:
Private isViewMode As Boolean = False
2. 初始化查看模式标识
修改带参数的构造函数,设置查看模式标识:
Public Sub New(Invno As Invoices) Me.New() ' 原有代码... DataGridView1.ReadOnly = True TextBox1.Text = Invno.INVNO ' 标记为查看模式 isViewMode = True End Sub
3. 在CellValidated事件中判断模式
在事件处理逻辑最开头加入判断,查看模式下直接退出:
Private Sub DataGridView1_CellValidated(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView1.CellValidated ' 查看模式下跳过事件逻辑 If isViewMode Then Return ' 原有事件代码... End Sub
4. 额外优化:避免类型转换异常
即使在录入模式,也应该先判断转换是否成功,防止意外报错:
Dim boundItem = TryCast(dgv.Rows(e.RowIndex).DataBoundItem, ProductFinaltesting) ' 先判断转换是否成功,再执行后续逻辑 If boundItem Is Nothing Then Return If p.Unit <> boundItem.Unit Or p.Prp <> boundItem.Prp Or p.Prs <> boundItem.Prs Then ' 原有赋值代码... End If
内容的提问来源于stack exchange,提问作者dlaksmi
相关产品推荐
相关产品推荐

