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

VB.NET实现可编辑转置DataGridView(列表/数据表)问题求助

VB.NET实现可编辑转置DataGridView(列表/DataTable绑定)及GetValue/SetValue错误修复

问题概述

需要实现两组DataGridView功能:

  • DataGridView1(绑定自定义对象列表):可编辑转置样式;对应DataGridView3为非转置、不可编辑状态
  • DataGridView2(绑定DataTable):可编辑转置样式;对应DataGridView4为非转置、不可编辑状态
    参考@RezaAghaei的C#转置代码转为VB.NET后,在Default Public Property Item(ByVal i As Integer) As Object属性中出现重载解析失败,没有可访问的GetValue/SetValue接受此参数数量错误。

错误原因

VB.NET中反射的GetValue/SetValue方法、DataTable的行/列访问逻辑与C#存在差异:

  • 反射调用属性的GetValue时必须传入目标对象实例,原代码遗漏了该参数
  • DataTable的行值访问不需要额外调用GetValue,直接通过索引即可操作

解决方案

针对列表和DataTable分别实现转置包装类,修正参数传递逻辑:

1. 列表绑定的转置包装类(用于DataGridView1)

Public Class TransposedList(Of T)
    Implements IList(Of Object)
    Private ReadOnly _originalList As IList(Of T)
    Private ReadOnly _propertyNames As String()

    Public Sub New(originalList As IList(Of T))
        _originalList = originalList
        _propertyNames = GetType(T).GetProperties().Select(Function(p) p.Name).ToArray()
    End Sub

    Public ReadOnly Property Count As Integer Implements ICollection(Of Object).Count
        Get
            Return _propertyNames.Length
        End Get
    End Property

    Public ReadOnly Property IsReadOnly As Boolean Implements ICollection(Of Object).IsReadOnly
        Get
            Return False
        End Get
    End Property

    Default Public Property Item(index As Integer) As Object Implements IList(Of Object).Item
        Get
            If _originalList.Count > 0 Then
                ' 传入对象实例,获取指定属性值
                Return GetType(T).GetProperty(_propertyNames(index)).GetValue(_originalList(0))
            End If
            Return Nothing
        End Get
        Set(value As Object)
            ' 遍历所有对象,设置指定属性值
            For Each item In _originalList
                GetType(T).GetProperty(_propertyNames(index)).SetValue(item, value)
            Next
        End Set
    End Property

    ' 实现IList接口其他方法(按需抛出不支持异常)
    Public Sub Add(item As Object) Implements ICollection(Of Object).Add
        Throw New NotSupportedException()
    End Sub

    Public Sub Clear() Implements ICollection(Of Object).Clear
        Throw New NotSupportedException()
    End Sub

    Public Function Contains(item As Object) As Boolean Implements ICollection(Of Object).Contains
        Return False
    End Function

    Public Sub CopyTo(array() As Object, arrayIndex As Integer) Implements ICollection(Of Object).CopyTo
        For i = 0 To Count - 1
            array(arrayIndex + i) = Me(i)
        Next
    End Sub

    Public Function GetEnumerator() As IEnumerator(Of Object) Implements IEnumerable(Of Object).GetEnumerator
        For i = 0 To Count - 1
            Yield Me(i)
        Next
    End Function

    Public Function IndexOf(item As Object) As Integer Implements IList(Of Object).IndexOf
        Return -1
    End Function

    Public Sub Insert(index As Integer, item As Object) Implements IList(Of Object).Insert
        Throw New NotSupportedException()
    End Sub

    Public Function Remove(item As Object) As Boolean Implements ICollection(Of Object).Remove
        Throw New NotSupportedException()
    End Function

    Public Sub RemoveAt(index As Integer) Implements IList(Of Object).RemoveAt
        Throw New NotSupportedException()
    End Sub

    Private Function IEnumerable_GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator
        Return GetEnumerator()
    End Function
End Class

2. DataTable绑定的转置包装类(用于DataGridView2)

Public Class TransposedDataTable
    Implements IList(Of Object)
    Private ReadOnly _originalTable As DataTable

    Public Sub New(originalTable As DataTable)
        _originalTable = originalTable
    End Sub

    Public ReadOnly Property Count As Integer Implements ICollection(Of Object).Count
        Get
            Return _originalTable.Columns.Count
        End Get
    End Property

    Public ReadOnly Property IsReadOnly As Boolean Implements ICollection(Of Object).IsReadOnly
        Get
            Return False
        End Get
    End Property

    Default Public Property Item(index As Integer) As Object Implements IList(Of Object).Item
        Get
            If _originalTable.Rows.Count > 0 Then
                ' 直接通过索引访问DataRow值
                Return _originalTable.Rows(0)(index)
            End If
            Return DBNull.Value
        End Get
        Set(value As Object)
            ' 遍历所有行,更新对应列的值
            For Each row In _originalTable.Rows
                row(index) = value
            Next
        End Set
    End Property

    ' 实现IList接口其他方法(按需抛出不支持异常)
    Public Sub Add(item As Object) Implements ICollection(Of Object).Add
        Throw New NotSupportedException()
    End Sub

    Public Sub Clear() Implements ICollection(Of Object).Clear
        Throw New NotSupportedException()
    End Sub

    Public Function Contains(item As Object) As Boolean Implements ICollection(Of Object).Contains
        Return False
    End Function

    Public Sub CopyTo(array() As Object, arrayIndex As Integer) Implements ICollection(Of Object).CopyTo
        For i = 0 To Count - 1
            array(arrayIndex + i) = Me(i)
        Next
    End Sub

    Public Function GetEnumerator() As IEnumerator(Of Object) Implements IEnumerable(Of Object).GetEnumerator
        For i = 0 To Count - 1
            Yield Me(i)
        Next
    End Function

    Public Function IndexOf(item As Object) As Integer Implements IList(Of Object).IndexOf
        Return -1
    End Function

    Public Sub Insert(index As Integer, item As Object) Implements IList(Of Object).Insert
        Throw New NotSupportedException()
    End Sub

    Public Function Remove(item As Object) As Boolean Implements ICollection(Of Object).Remove
        Throw New NotSupportedException()
    End Function

    Public Sub RemoveAt(index As Integer) Implements IList(Of Object).RemoveAt
        Throw New NotSupportedException()
    End Sub

    Private Function IEnumerable_GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator
        Return GetEnumerator()
    End Function
End Class

3. 窗体绑定示例代码

' 自定义列表绑定类
Public Class Person
    Public Property Name As String
    Public Property Age As Integer
    Public Property Email As String
End Class

Private Sub Form_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    ' 列表绑定逻辑
    Dim personList As New List(Of Person) From {
        New Person With {.Name = "张三", .Age = 25, .Email = "zhangsan@test.com"},
        New Person With {.Name = "李四", .Age = 30, .Email = "lisi@test.com"}
    }
    ' DataGridView1:可编辑转置
    DataGridView1.DataSource = New TransposedList(Of Person)(personList)
    ' 设置列标题与行标题
    For i = 0 To DataGridView1.Columns.Count - 1
        DataGridView1.Columns(i).HeaderText = "值"
    Next
    DataGridView1.Columns.Insert(0, New DataGridViewTextBoxColumn() With {.HeaderText = "属性名", .ReadOnly = True})
    For i = 0 To DataGridView1.Rows.Count - 1
        DataGridView1.Rows(i).Cells(0).Value = GetType(Person).GetProperties()(i).Name
    Next
    ' DataGridView3:非转置不可编辑
    DataGridView3.DataSource = personList
    DataGridView3.ReadOnly = True

    ' DataTable绑定逻辑
    Dim dt As New DataTable()
    dt.Columns.Add("产品名称")
    dt.Columns.Add("价格")
    dt.Columns.Add("库存")
    dt.Rows.Add("手机", 2999, 100)
    dt.Rows.Add("电脑", 5999, 50)
    ' DataGridView2:可编辑转置
    DataGridView2.DataSource = New TransposedDataTable(dt)
    ' 设置列标题与行标题
    For i = 0 To DataGridView2.Columns.Count - 1
        DataGridView2.Columns(i).HeaderText = "值"
    Next
    DataGridView2.Columns.Insert(0, New DataGridViewTextBoxColumn() With {.HeaderText = "列名", .ReadOnly = True})
    For i = 0 To DataGridView2.Rows.Count - 1
        DataGridView2.Rows(i).Cells(0).Value = dt.Columns(i).ColumnName
    Next
    ' DataGridView4:非转置不可编辑
    DataGridView4.DataSource = dt
    DataGridView4.ReadOnly = True
End Sub

修复说明

  1. 列表转置类中,调用反射GetValue/SetValue时明确传入目标对象实例,解决参数数量不足的问题
  2. DataTable转置类中,直接通过DataRow(index)访问值,避免错误调用GetValue方法
  3. 手动添加行标题列,显示原属性名/列名,保证转置后的界面可读性

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 20:23:19