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

VB.NET中DataTable空值列查询及跨窗体DataGrid数据同步异常排查

问题描述

我想通过DataTable Select实现从Form2的DataGridView(数据源为DataTable)到Form1的DataGridView(数据源为DataTable)的数据变更操作,但Form1中DataGridView的显示结果与预期不符,怀疑代码存在问题。

Form1中DataGridView的当前结果

预期结果
Column1Column2Column3Column4Qty
001TEST1TEST1TEST11
001TEST1TEST11
001TEST11
001TEST1TEST11
002TEST2TEST2TEST21
现有代码

Form1代码

Public Class Form1
    Private table1 As New DataTable
   Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

        table1.Columns.Add(New DataColumn("Column1", GetType(String)))
        table1.Columns.Add(New DataColumn("Column2", GetType(String)))
        table1.Columns.Add(New DataColumn("Column3", GetType(String)))
        table1.Columns.Add(New DataColumn("Column4", GetType(String)))
        table1.Columns.Add(New DataColumn("Qty", GetType(Integer)))
        DataGridView1.DataSource = table1
    End Sub
 Private Sub BTNAdd_Click(sender As Object, e As EventArgs) Handles BTNAdd.Click
        Dim Column2 As String = TextBox2.Text.Trim()
        Dim Column1 = TextBox1.Text.Trim()
        Using frm = New Form2(Column2)

            If frm.ShowDialog() = DialogResult.OK Then
                Dim datarow As DataRow = Nothing
                Dim Column3 = frm.DataGridView1.CurrentRow.Cells(3).Value?.ToString()
                Dim Column4 = frm.DataGridView1.CurrentRow.Cells(4).Value?.ToString()
                If table1.Rows.Cast(Of DataRow).Any() Then
                    datarow = table1.Select($"Column1 = '{Column1}' AND Column2 = '{Column2}' AND Column3 = '{Column3}' OR Column3 IS NULL AND Column4 = '{Column4}' OR Column4 IS NULL").FirstOrDefault()
                End If
                If datarow IsNot Nothing Then
                    Dim qty = If(datarow("Qty") Is DBNull.Value, 0, datarow.Field(Of Integer)("Qty"))
                    datarow.SetField("Qty", qty + 1)
                    Return
                Else
                End If
                Try
                    For Each row2 As DataGridViewRow In frm.DataGridView1.Rows
                        Dim isselect As Boolean = Convert.ToBoolean(row2.Cells("checkboxcolumn").Value)
                        If isselect Then
                            table1.Rows.Add(Column1, Column2, Column3, Column4, 1)
                            TextBox1.Clear()
                            TextBox2.Clear()
                        End If
                    Next
                Catch ex As Exception
                    MessageBox.Show(ex.Message)
                End Try
            Else

                Return
            End If
        End Using
    End Sub
End Class

Form2代码

Public Class Form2
    Sub New()
        InitializeComponent()
    End Sub
    Public Function ConvertToList(Of T)(ByVal dt As DataTable) As List(Of T)
        Dim columnNames = dt.Columns.Cast(Of DataColumn)().Select(Function(c) c.ColumnName).ToList()
        Dim properties = GetType(T).GetProperties()
        Return dt.AsEnumerable().Select(Function(row)
                                            Dim objT = Activator.CreateInstance(Of T)()
                                            For Each pro In properties
                                                If columnNames.Contains(pro.Name) Then
                                                    Dim pI As PropertyInfo = objT.GetType().GetProperty(pro.Name)
                                                    pro.SetValue(objT, If(row(pro.Name) Is DBNull.Value, Nothing, Convert.ChangeType(row(pro.Name), pI.PropertyType)))
                                                End If
                                            Next pro
                                            Return objT
                                        End Function).ToList()
    End Function

    Public Sub New(Column2 As String)
        Me.New
        Dim table2 As New DataTable("Players")
        table2.Columns.Add(New DataColumn("Column1", GetType(String)))
        table2.Columns.Add(New DataColumn("Column2", GetType(String)))
        table2.Columns.Add(New DataColumn("Column3", GetType(String)))
        table2.Columns.Add(New DataColumn("Column4", GetType(String)))
        table2.Rows.Add("001", "TEST1", "TEST1", "TEST1")
        table2.Rows.Add("001", "TEST1", "TEST1", "")
        table2.Rows.Add("001", "TEST1", "", "")
        table2.Rows.Add("001", "TEST1", "", "TEST1")
        table2.Rows.Add("002", "TEST2", "", "TEST2")
        DataGridView1.DataSource = ConvertToList(Of Table2)(table2)
        Dim CheckedBoxColumn As New DataGridViewCheckBoxColumn
        CheckedBoxColumn.Width = 40
        CheckedBoxColumn.Name = "checkboxcolumn"
        CheckedBoxColumn.HeaderText = "Check"
        DataGridView1.Columns.Insert(0, CheckedBoxColumn)
    End Sub

    Private Sub BtnOK_Click(sender As Object, e As EventArgs) Handles BtnOK.Click
        DialogResult = DialogResult.OK
    End Sub
End Class
Public Class Table2

    Public Property Column1() As String
    Public Property Column2() As String
    Public Property Column3() As String
    Public Property Column4() As String

End Class
问题分析与修复方案

核心问题1:Select语句逻辑错误

当前table1.Select的条件存在运算符优先级混乱,OR优先级低于AND,导致匹配逻辑完全偏离预期;同时Form2中存储的是空字符串"",但代码用Column3 IS NULL无法匹配空字符串(空字符串和DBNull是不同概念)。

核心问题2:选中行数据获取错误

代码仅提取了CurrentRow的Column3/Column4值,循环所有选中行时重复使用该值,导致所有选中行都被添加为同一数据,而非各自的行数据。

修复后的Form1代码

Public Class Form1
    Private table1 As New DataTable
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        table1.Columns.Add(New DataColumn("Column1", GetType(String)))
        table1.Columns.Add(New DataColumn("Column2", GetType(String)))
        table1.Columns.Add(New DataColumn("Column3", GetType(String)))
        table1.Columns.Add(New DataColumn("Column4", GetType(String)))
        table1.Columns.Add(New DataColumn("Qty", GetType(Integer)))
        DataGridView1.DataSource = table1
    End Sub

    Private Sub BTNAdd_Click(sender As Object, e As EventArgs) Handles BTNAdd.Click
        Dim Column2 As String = TextBox2.Text.Trim()
        Dim Column1 = TextBox1.Text.Trim()
        Using frm = New Form2(Column2)
            If frm.ShowDialog() = DialogResult.OK Then
                Try
                    For Each row2 As DataGridViewRow In frm.DataGridView1.Rows
                        ' 跳过DataGridView自动生成的空白新行
                        If row2.IsNewRow Then Continue For
                        
                        Dim isselect As Boolean = Convert.ToBoolean(row2.Cells("checkboxcolumn").Value)
                        If isselect Then
                            ' 获取当前选中行的真实数据
                            Dim rowColumn1 = row2.Cells(1).Value?.ToString()
                            Dim rowColumn2 = row2.Cells(2).Value?.ToString()
                            Dim rowColumn3 = row2.Cells(3).Value?.ToString()
                            Dim rowColumn4 = row2.Cells(4).Value?.ToString()

                            ' 修正过滤条件:精准匹配所有列,兼容空字符串
                            Dim filter As String = $"Column1 = '{rowColumn1}' AND Column2 = '{rowColumn2}' " &
                                                  $"AND (Column3 = '{If(String.IsNullOrEmpty(rowColumn3), "", rowColumn3)}' OR Column3 = '') " &
                                                  $"AND (Column4 = '{If(String.IsNullOrEmpty(rowColumn4), "", rowColumn4)}' OR Column4 = '')"
                            Dim matchRows = table1.Select(filter)
                            If matchRows.Any() Then
                                ' 找到匹配行,数量+1
                                Dim qty = If(matchRows(0)("Qty") Is DBNull.Value, 0, matchRows(0).Field(Of Integer)("Qty"))
                                matchRows(0).SetField("Qty", qty + 1)
                            Else
                                ' 无匹配行,新增数据
                                table1.Rows.Add(rowColumn1, rowColumn2, rowColumn3, rowColumn4, 1)
                            End If
                        End If
                    Next
                    TextBox1.Clear()
                    TextBox2.Clear()
                Catch ex As Exception
                    MessageBox.Show(ex.Message)
                End Try
            Else
                Return
            End If
        End Using
    End Sub
End Class

优化说明

  1. 移除无效的CurrentRow数据提取,直接遍历选中行时获取对应单元格的真实数据
  2. 修正Select过滤条件,准确匹配空字符串,确保逻辑符合预期
  3. 添加空白新行判断,避免处理DataGridView自动生成的无效行
  4. 调整数据处理逻辑,保证每一行选中数据都被独立处理,不会重复添加同一内容

内容的提问来源于stack exchange,提问作者roy

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 22:39:53