在嵌套的For循环中获取DataGridView单元格值

时间:2016-11-11 16:46:12

标签: .net vb.net validation datagridview

我在DataGridView上显示了一些数据,在btnSave_Click事件中,我正在调用子程序来验证网格中的数据,然后将其保存到我的数据库中。

我正在这样做的方法是为每一行使用一个循环,并为每个列使用另一个for循环。

然后我需要比较它正在验证的单元格值中的每个char(row dr,cell dc)。但是,我无法解决使用行/列坐标来获取单元格中的值的方法。

有点难以解释我的意思,但是在这段代码中,我在前2行设置For Loops,然后在第3行设置,注意If IsDBNull(dc.TextInCell) - TextInCell是我的意思需要更换。

In Row;博士和专栏; dc,我需要验证存储在该单元格中的值...

For Each dr As DataGridViewRow In dgvImport.Rows
   For Each dc As DataGridViewColumn In dgvImport.Columns
     If dc.HeaderText = "Product Code" Then
       If IsDBNull(dc.TextInCell) = True Or dc.TextInCell = Nothing Or dc.TextInCell = "" Then
          Me.Cursor = Cursors.Default
          MsgBox("Import failed. One or more required fields were not entered", MsgBoxStyle.OkOnly, "Error")
          Exit Sub
        End If
        For Each c As Char In dc.TextInCell
         If Not Char.IsLetterOrDigit(c) Then
          If Not Char.IsWhiteSpace(c) Then
           If c <> "&" AndAlso c <> "-" AndAlso c <> "(" AndAlso c <> ")" Then
             Me.Cursor = Cursors.Default
             MsgBox("Import failed. One or more cells contains an invalid character", MsgBoxStyle.OkOnly, "Error")
             Exit Sub
           End If
          End If
         End If
Next

如何从此处将单元格值转换为变量以通过验证发送?

1 个答案:

答案 0 :(得分:3)

迭代数据表中的行(几乎)总是比通过控件的行更快。您的代码中至少还存在一个低效率:

For Each dr As DataGridViewRow In dgvImport.Rows
    For Each dc As DataGridViewColumn In dgvImport.Columns
        If dc.HeaderText = "Product Code" Then

您不需要为每一行找到目标列 - 它将在每行的相同索引处。

我不知道这些预期的模式是什么,但是如果有一个定义的模式,如“N-LLL-AAA-NLN”(例如:9-WDM-6K6-6ZC),你可能想要查看 { {3}} 用于全面的模式测试。例如,你的代码基本上只是在字符串中测试一组有限的特殊字符 where ;如果有(不应该在任何)之前?

你肯定需要摆弄实际的验证码,但这要快很多倍:

'... code to fill the DT
' add a column to track if the row is valid
dtSample.Columns.Add(New DataColumn("IsValid", GetType(Boolean)))

Dim specialChars = "&-()"
Dim txt As String = ""
Dim bValid As Boolean
Dim prodIndex As Int32

' index of the target column using the column name
prodIndex = dtSample.Columns.IndexOf("ProductCode")  

For Each dr As DataRow In dtProduct.Rows
    ' get the text
    txt = dr.Field(Of String)(prodIndex)

    ' first check for nothing from DBNull
    bValid = String.IsNullOrEmpty(txt) = False
    ' if there is text data, check the content
    If bValid Then
        ' each char must be letter, digit or authorized special char
        For n As Int32 = 0 To txt.Length - 1
            If Char.IsLetterOrDigit(txt(n)) = False AndAlso
                        specialChars.Contains(txt(n)) = False Then
                bValid = False
                Exit For
            End If
        Next
    End If
    ' unabiguously set the column for each row
    dr("IsValid") = bValid
Next

dgv1.DataSource = dtSample
' hide our scratch column
dgv1.Columns("IsValid").Visible = False

结果:

RegEx

RowPrePaint事件中未显示2-3行,为IsValid为假的行着色。更重要的是,它很快: 125毫秒来处理75,000行;通过DGV挖掘并反复找到相同的列需要7-8秒。

即使没有RegEx,您也可以测试特定位置的特殊字符(假设固定模式)。例如,要测试"A-78*X(2012)"

bValid = pcode(1) = "-"c AndAlso
         pcode(4) = "*"c AndAlso
         pcode(6) = "("c AndAlso
         pcode(11) = ")"c

您还可以按字符分割字符串,以便测试parts(3)是2010年和2015年之间的值,或者其他任何内容,如果您想要执行该级别的测试。你做的越多,RegEX就会越有用。