如何引用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
相关产品推荐
相关产品推荐

