【问题标题】:Get DataGridView cell value in nested For Loops在嵌套的 For 循环中获取 DataGridView 单元格值
【发布时间】:2017-03-25 22:52:21
【问题描述】:

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

我这样做的方式是对每一行使用一个循环,并在该循环内对每一列使用另一个 for 循环。

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

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

在行中;博士和专栏; 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

如何从这里将单元格值放入变量中以通过验证发送它?

【问题讨论】:

  • 有些事件可以让您随时进行验证,这样您就可以告诉用户他们有一个错误当他们出错时,而不是“某处出现错误”这一页”。 CellValidating 是一种,CellLeave 也是一种可能
  • @Plutonix 不确定这里是否可行。这是从 Excel 电子表格中选择的数据,DataSource 是我选择后填写的DataTable
  • 在这种情况下,我绝对不会循环遍历 DGV,而是遍历 DataTable 行。您可以添加一列来指示哪些通过,哪些失败并提供一些视觉提示
  • @Plutonix 问题在于我不能使用列标题来决定需要什么验证。不同的用户在他们的电子表格中会有不同的列标题(但总是以相同的顺序),所以使用 DGV 意味着我可以设置索引标题,这样就不用担心用户在电子表格中调用它的内容。
  • 如果您知道顺序,您可以使用它来触发这个或那个验证。您也可以转储大部分或所有代码来代替 RegEx。如果他们将坏数据编辑为好数据,您可能不得不再次调用它们,以便您检查它是否良好。

标签: .net vb.net validation datagridview


【解决方案1】:

迭代数据表中的行(几乎)总是比通过控件获取根更快。您的代码中至少还有一处效率低下:

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)你可能想看看RegEx 用于全面的模式测试。例如,您的代码基本上只是测试字符串中的一组有限的特殊字符 anywhere;如果有(,它不应该在任何)之前吗?

您肯定需要修改实际的验证代码,但这要快很多倍:

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

结果:

未显示 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 就越有用。

【讨论】:

  • 我只是纠正了一点点逻辑。例如,每当bValidFalse 时,它都会将网格的第一行设置为显示为假,即使它是第4 行。否则没关系
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-01-28
  • 2013-06-05
  • 2021-08-08
  • 2023-03-28
  • 2017-03-14
  • 1970-01-01
  • 2013-10-26
相关资源
最近更新 更多