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

如何引用GridView中自动生成列的成员?

问题:获取GridView自动生成列的引用进行类型校验

由于数据源来自SQL数据库中的多个不同表,字段无法提前确定,因此采用自动生成列的方式。目标是在用户更新数据时,根据存储的字段元信息进行类型校验,但DataBind()执行后,GridView.Columns集合中并未生成可引用的对象,导致无法获取这些列的引用。

编写的代码在获取列HeaderText时执行失败:

Private Sub gvwResults_CommitEditOperation(sender As Object, e As GridViewUpdateEventArgs) Handles gvwResults.RowUpdating
    Try
    Dim fields As List(Of UITableField) = CType(Session("TableFields"), List(Of UITableField))

    Dim row As GridViewRow = gvwResults.Rows(e.RowIndex)
    For Each cell As TableCell In row.Cells
        'first check: confirm all types are correct

        'get cell column index so we can find the column so we can get the header text so we can match that against the UI fields
        'UI fields in turn have the appropriate type per field, so then parse the input text and see if they match
        Dim col As Integer = row.Cells.GetCellIndex(cell)
        If {0, 1}.Contains(col) Then Continue For   'ignore edit and delete columns
        
        'SO: This is the line where it fails
        Dim header As String = gvwResults.Columns(col).HeaderText
        Dim validType As Type = fields.First(Function(t) t.Name = header).DataType

        'SO: This is all untested, forgive me if you see obvious errors here, haven't gotten to it yet
        Dim value As Object
        If Double.TryParse(cell.Text, value) Then
            'tryparse assigns if parseable, no action necessary
        ElseIf Integer.TryParse(cell.Text, value) Then
            'see first if
        Else
            value = cell.Text   'default to string and pray for the best
        End If

        'value is at this point either the Type object for double, integer, or string as appropriate to the entered data
        'if that matches the indicated field from the Xml data, we're all peachy
        If Not Object.Equals(validType, value.GetType()) Then
            Throw New DataException($"Invalid data supplied to edited row in column {header}")
        End If
    Next
    Catch ex As DataException 'TODO: handle stuff
    Catch ex As Exception
    End Try
End Sub

每个TableCell都有列索引,但该索引无法用于获取对应的列对象,尝试通过TableCell.Parent获取,返回的是GridViewRow而非列。请问是否有方法获取这些自动生成列的引用?还是必须为每个表单独创建页面?


解决方案

GridView的Columns集合仅存储手动定义的列,自动生成的列不会被加入该集合,所以直接通过索引访问Columns(col)会报错。以下是几种可行的解决办法,无需为每个表单独创建页面:

方法1:直接利用数据源的DataTable元数据

绑定GridView时,将数据源DataTable存入Session,更新时直接从DataTable的Columns集合获取字段名和类型信息,完全替代通过HeaderText匹配的逻辑:

绑定GridView时的代码

' 从SQL数据库获取数据并绑定
Dim dt As DataTable = GetDataFromSql() ' 替换为你的SQL查询方法
Session("BoundDataTable") = dt
gvwResults.DataSource = dt
gvwResults.DataBind()

RowUpdating事件修改后的代码

Private Sub gvwResults_RowUpdating(sender As Object, e As GridViewUpdateEventArgs) Handles gvwResults.RowUpdating
    Try
        Dim dt As DataTable = CType(Session("BoundDataTable"), DataTable)
        Dim fields As List(Of UITableField) = CType(Session("TableFields"), List(Of UITableField))
        Dim row As GridViewRow = gvwResults.Rows(e.RowIndex)
        
        ' 跳过前两列(编辑/删除按钮列)
        For colIndex As Integer = 2 To row.Cells.Count - 1
            ' 对应DataTable中的列索引需要减去按钮列的数量(2)
            Dim columnName As String = dt.Columns(colIndex - 2).ColumnName
            Dim validType As Type = fields.First(Function(t) t.Name = columnName).DataType
            
            Dim cellText As String = row.Cells(colIndex).Text
            Dim value As Object = Nothing
            Dim isValid As Boolean = True
            
            ' 根据目标类型校验输入
            Select Case validType.Name
                Case "Int32"
                    isValid = Integer.TryParse(cellText, CType(value, Integer))
                Case "Double"
                    isValid = Double.TryParse(cellText, CType(value, Double))
                Case "String"
                    value = cellText
                ' 可扩展支持更多数据类型(如DateTime、Boolean等)
                Case Else
                    value = cellText
            End Select
            
            If Not isValid Then
                Throw New DataException($"列 {columnName} 输入的数据类型无效")
            End If
        Next
    Catch ex As DataException
        ' 取消更新并刷新GridView
        e.Cancel = True
        gvwResults.EditIndex = -1
        gvwResults.DataBind()
        ' 可添加Label显示错误提示
    Catch ex As Exception
        ' 处理其他异常
    End Try
End Sub

方法2:在RowDataBound事件中提前存储表头映射

利用RowDataBound事件绑定表头时,将列索引与HeaderText的对应关系存入Session,后续更新时直接取用:

RowDataBound事件代码

Private Sub gvwResults_RowDataBound(sender As Object, e As GridViewRowEventArgs) Handles gvwResults.RowDataBound
    If e.Row.RowType = DataControlRowType.Header Then
        Dim headerMap As New Dictionary(Of Integer, String)()
        ' 跳过前两列按钮列
        For i As Integer = 2 To e.Row.Cells.Count - 1
            headerMap.Add(i, e.Row.Cells(i).Text)
        Next
        Session("HeaderColumnMap") = headerMap
    End If
End Sub

RowUpdating事件中使用映射

Private Sub gvwResults_RowUpdating(sender As Object, e As GridViewUpdateEventArgs) Handles gvwResults.RowUpdating
    Try
        Dim fields As List(Of UITableField) = CType(Session("TableFields"), List(Of UITableField))
        Dim headerMap As Dictionary(Of Integer, String) = CType(Session("HeaderColumnMap"), Dictionary(Of Integer, String))
        Dim row As GridViewRow = gvwResults.Rows(e.RowIndex)
        
        For Each cell As TableCell In row.Cells
            Dim col As Integer = row.Cells.GetCellIndex(cell)
            If {0, 1}.Contains(col) Then Continue For
            
            ' 从映射中获取HeaderText
            If headerMap.ContainsKey(col) Then
                Dim header As String = headerMap(col)
                Dim validType As Type = fields.First(Function(t) t.Name = header).DataType
                
                ' 类型校验逻辑
                Dim value As Object
                If Double.TryParse(cell.Text, value) Then
                    ' 解析成功
                ElseIf Integer.TryParse(cell.Text, value) Then
                    ' 解析成功
                Else
                    value = cell.Text
                End If
                
                If Not Object.Equals(validType, value.GetType()) Then
                    Throw New DataException($"列 {header} 输入的数据类型无效")
                End If
            End If
        Next
    Catch ex As DataException
        e.Cancel = True
        gvwResults.EditIndex = -1
        gvwResults.DataBind()
    Catch ex As Exception
        ' 处理其他异常
    End Try
End Sub

方法3:使用GridViewUpdateEventArgs.NewValues集合(最简洁)

GridViewUpdateEventArgs的NewValues集合直接存储了用户编辑后的所有字段名和对应值,自动跳过按钮列,无需处理单元格索引:

Private Sub gvwResults_RowUpdating(sender As Object, e As GridViewUpdateEventArgs) Handles gvwResults.RowUpdating
    Try
        Dim fields As List(Of UITableField) = CType(Session("TableFields"), List(Of UITableField))
        
        For Each entry As DictionaryEntry In e.NewValues
            Dim columnName As String = entry.Key.ToString()
            Dim inputValue As String = entry.Value.ToString()
            Dim validType As Type = fields.First(Function(t) t.Name = columnName).DataType
            
            Dim value As Object = Nothing
            Dim isValid As Boolean = True
            
            ' 类型校验
            Select Case validType.Name
                Case "Int32"
                    isValid = Integer.TryParse(inputValue, CType(value, Integer))
                Case "Double"
                    isValid = Double.TryParse(inputValue, CType(value, Double))
                Case "String"
                    value = inputValue
                Case Else
                    value = inputValue
            End Select
            
            If Not isValid Then
                Throw New DataException($"列 {columnName} 输入的数据类型无效")
            End If
        Next
    Catch ex As DataException
        ' 取消更新并提示错误
        e.Cancel = True
        gvwResults.EditIndex = -1
        gvwResults.DataBind()
    Catch ex As Exception
        ' 处理其他异常
    End Try
End Sub

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 18:24:54