简体   繁体   English

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

[英]Get DataGridView cell value in nested For Loops

I've got some data displayed on a DataGridView , and in my btnSave_Click event, I'm calling a subroutine to validate the data in the grid before saving it into my database. 我在DataGridView上显示了一些数据,在我的btnSave_Click事件中,我调用了一个子例程来验证网格中的数据,然后将其保存到我的数据库中。

The way I'm doing it is by using a loop for each row and inside that loop using another for loop, for each column. 我这样做的方法是为每一行使用一个循环,在每个行中使用另一个for循环。

I need to then compare each char in the cell value that it's validating (row dr, cell dc). 然后我需要比较它正在验证的单元格值中的每个字符(行dr,单元直流)。 However, I cannot work out the way to use the row/column co-ordinates to get the value in the cell. 但是,我无法解决使用行/列坐标来获取单元格中的值的方法。

It's a little hard to explain what I mean, but in this code I have the For Loops set up on the first 2 lines, then on the third line, notice If IsDBNull(dc.TextInCell) - TextInCell is what I need to replace. 这有点难以解释我的意思,但是在这段代码中,我在前2行设置For Loops ,然后在第3行,注意If IsDBNull(dc.TextInCell) - TextInCell是我需要替换的。

In Row; 在排队; dr and Column; 博士和专栏; dc, I need to then validate the value stored in that cell... 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

How do I get the cell value into a variable from here to send it through the validation? 如何从此处将单元格值转换为变量以通过验证发送?

It will (almost) always be faster to iterate the rows in the datatable than to root thru the control. 它(几乎)总是更快地迭代数据表中的行而不是通过控件的根。 There is also at least one inefficiency in your code: 您的代码中至少还有一个效率低下:

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

You dont need to find the target column for each row - it will be at the same index for each row. 您不需要为每一行找到目标列 - 它将在每行的相同索引处。

I dont know what the expected pattern is for these, but if there is a defined pattern like "N-LLL-AAA-NLN" (eg: 9-WDM-6K6-6ZC ) you might want to look into RegEx for comprehensive pattern testing. 我不知道这些预期的模式是什么,但如果有一个定义的模式,如“N-LLL-AAA-NLN”(例如: 9-WDM-6K6-6ZC ),您可能需要查看RegEx以进行全面的模式测试。 For instance your code is basically just testing for a limited set of special characters anywhere in the string; 例如,您的代码基本上只是在字符串中的任何位置测试一组有限的特殊字符; if there is a ( shouldn't it be before any ) ? 如果有(不应该在任何之前)

You will surely need to fiddle with the actual validation code, but this is many times faster: 你肯定需要摆弄实际的验证代码,但这要快很多倍:

'... 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

Results: 结果:

在此输入图像描述

Not shown is 2-3 lines in the RowPrePaint event to color the rows where IsValid is false. 未显示RowPrePaint事件中的2-3行,以对IsValid为false的行着色。 More importantly, it is fast: 125 milliseconds to process 75,000 rows; 更重要的是,它很快:处理75,000行125毫秒 ; digging thru the DGV and finding the same column over and over takes 7-8 secs. 通过DGV挖掘并反复找到相同的列需要7-8秒。

Even without RegEx, you can test for special characters at specific locations (assuming a fixed pattern). 即使没有RegEx,您也可以测试特定位置的特殊字符(假设固定模式)。 For instance, to test "A-78*X(2012)" : 例如,要测试"A-78*X(2012)"

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

You could also split the string by those characters in order to test that parts(3) is a value between 2010 and 2015 or whatever, if you wanted to perform that level of testing. 您还可以按字符分割字符串,以便测试parts(3)是2010年和2015年之间的值或其他任何值,如果您想要执行该级别的测试。 The more of that you do, the more useful RegEX would be. 你做的越多,RegEX就会越有用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM