vb.netwinformsdatatabledatagridviewienumerable

Transposed editable DataGridView from list and datatable with vb.net


I'm Trying make Transposed editable DataGridView from list and datatable with vb.net.

so in Datagridview1 Transposed editable (From list) with result in Datagridview1 non Transposed and non editable and in Datagridview2 Transposed editable (From datatable) with result in Datagridview4 non Transposed and non editable.

I found the answer from @RezaAghaei (below link) in the C# programming language but I tried the code with the programming language VB.NET there was an error in method Default Public Property Item(ByVal i As Integer) As Object

Link

Please Guide me

Thanks

Result below code Answer from the link above with conversion to vb.net

Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Linq
Public Class RotatedListDataSource(Of T)
    Inherits List(Of RotatedItem)

    Public ReadOnly Property List As List(Of T)
    Public Sub New(ByVal list As List(Of T))
        Me.List = list
        Me.AddRange(GetType(T).GetProperties().Select(Function(p) New RotatedItem(p.Name, list.Cast(Of Object)().ToArray(), p.PropertyType)))
    End Sub
End Class
Public Class RotatedItem
    Inherits CustomTypeDescriptor

    Public ReadOnly Property PropertyName As String
    Private data() As Object
    Public ReadOnly Property Type As Type
    Public Sub New(ByVal propertyName As String, ByVal data() As Object, ByVal type As Type)
        Me.PropertyName = propertyName
        Me.data = data
        Me.Type = type
    End Sub
    Public Overrides Function GetProperties() As PropertyDescriptorCollection
        Return Me.GetProperties(New Attribute() {})
    End Function
    Public Overrides Function GetProperties(ByVal attributes() As Attribute) As PropertyDescriptorCollection
        Dim properties = New List(Of PropertyDescriptor)()
        properties.Add(New PropertyNameProperty(New Attribute() {New BrowsableAttribute(False)}))
        For i As Integer = 0 To data.Length - 1
            properties.Add(New IndexProperty(i, GetType(Object), New Attribute() {}))
        Next i
        Return New PropertyDescriptorCollection(properties.ToArray())
    End Function
    Default Public Property Item(ByVal i As Integer) As Object
        Get
'Error below line Overload resolution failed because no accessible 'GetValue' accepts this number of arguments.
            Return data(i).GetType().GetProperty(PropertyName).GetValue(data(i))
        End Get
        Set(ByVal value As Object)
'Error below line Overload resolution failed because no accessible 'SetValue' accepts this number of arguments.
            data(i).GetType().GetProperty(PropertyName).SetValue(data(i), Convert.ChangeType(value, Type))
        End Set
    End Property
End Class
Public Class IndexProperty
    Inherits PropertyDescriptor

    Private index As Integer
    Private type As Type
    Public Sub New(ByVal index As Integer, ByVal type As Type, ByVal attributes() As Attribute)
        MyBase.New(index.ToString(), attributes)
        Me.index = index
        Me.type = type
    End Sub
    Public Overrides ReadOnly Property ComponentType As Type
        Get
            Return GetType(RotatedItem)
        End Get
    End Property
    Public Overrides ReadOnly Property IsReadOnly As Boolean
        Get
            Return False
        End Get
    End Property
    Public Overrides ReadOnly Property PropertyType As Type
        Get
            Return type
        End Get
    End Property
    Public Overrides Function CanResetValue(ByVal component As Object) As Boolean
        Return False
    End Function
    Public Overrides Function GetValue(ByVal component As Object) As Object
        Return DirectCast(component, RotatedItem)(index)
    End Function
    Public Overrides Sub ResetValue(ByVal component As Object)
    End Sub
    Public Overrides Sub SetValue(ByVal component As Object, ByVal value As Object)
        DirectCast(component, RotatedItem)(index) = value
    End Sub
    Public Overrides Function ShouldSerializeValue(ByVal component As Object) As Boolean
        Return True
    End Function
End Class
Public Class PropertyNameProperty
    Inherits PropertyDescriptor

    Public Sub New(ByVal attributes() As Attribute)
        MyBase.New(NameOf(RotatedItem.PropertyName), attributes)
    End Sub
    Public Overrides ReadOnly Property ComponentType As Type
        Get
            Return GetType(RotatedItem)
        End Get
    End Property
    Public Overrides ReadOnly Property IsReadOnly As Boolean
        Get
            Return True
        End Get
    End Property
    Public Overrides ReadOnly Property PropertyType As Type
        Get
            Return GetType(String)
        End Get
    End Property
    Public Overrides Function CanResetValue(ByVal component As Object) As Boolean
        Return False
    End Function
    Public Overrides Function GetValue(ByVal component As Object) As Object
        Return DirectCast(component, RotatedItem).PropertyName
    End Function
    Public Overrides Sub ResetValue(ByVal component As Object)
    End Sub
    Public Overrides Sub SetValue(ByVal component As Object, ByVal value As Object)
    End Sub
    Public Overrides Function ShouldSerializeValue(ByVal component As Object) As Boolean
        Return True
    End Function
End Class

Public Class Form1
    Private Sub LISTEMP()
        Dim Product As New List(Of Product)() From {
    New Product() With {
        .Codeproduct = "SHIRTA",
        .Productname = "SHIRT WHITE",
        .Size = "S",
        .Qty = 1
    },
      New Product() With {
        .Codeproduct = "SHIRTB",
        .Productname = "SHIRT BLACK",
        .Size = "M",
        .Qty = 1
    },
    New Product() With {
        .Codeproduct = "SHIRTC",
        .Productname = "SHIRT YELLOW",
        .Size = "L",
        .Qty = 1
    },
    New Product() With {
        .Codeproduct = "SHIRTD",
        .Productname = "SHIRT GREEN",
        .Size = "XL",
        .Qty = 1
    },
   New Product() With {
        .Codeproduct = "SHIRTE",
        .Productname = "SHIRT YELLOW",
        .Size = "2L",
        .Qty = 1
    }
}
     DataGridView1.DataSource = Product.ToList()
    End Sub
    Private Sub datatableEMP()
        Dim Product As New DataTable()
        Product.Columns.Add("Codeproduct", GetType(String))
        Product.Columns.Add("Productname", GetType(String))
        Product.Columns.Add("Size", GetType(String))
         Product.Columns.Add("Qty", GetType(Integer))
        Product.Rows.Add("SHIRTA", "SHIRT WHITE", "S", 1)
        Product.Rows.Add("SHIRTB", "SHIRT BLACK", "M", 1)
        Product.Rows.Add("SHIRTC", "SHIRT YELLOW", "L", 1)
        Product.Rows.Add("SHIRTD", "SHIRT GREEN", "XL", 1)
        Product.Rows.Add("SHIRTE", "SHIRT YELLOW", "2L", 1)


        DataGridView2.DataSource = Product
    End Sub


    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        LISTEMP()
        datatableEMP()
    End Sub
End Class

Public Class Product
    Public Property Codeproduct As String
    Public Property Productname As String
    Public Property Size As String
    Public Property Qty As Integer
End Class

result from my code

screenshot result code 25102024

Desired result

Datagridview1 Transposed editable (From list)

Codeproduct Productname S M L XL 2L
SHIRTA SHIRT WHITE 1
SHIRTB SHIRT BLACK 1
SHIRTC SHIRT YELLOW 1
SHIRTD SHIRT GREEN 1
SHIRTE SHIRT YELLOW 1

Datagridview2 Transposed editable (From Datatable)

Codeproduct Productname S M L XL 2L
SHIRTA SHIRT WHITE 1
SHIRTB SHIRT BLACK 1
SHIRTC SHIRT YELLOW 1
SHIRTD SHIRT GREEN 1
SHIRTE SHIRT YELLOW 1

Datagridview3 result Non Transposed and non editable from datagridview1 (From list)

Codeproduct Productname Size Qty
SHIRTA SHIRT WHITE S 1
SHIRTB SHIRT BLACK M 1
SHIRTC SHIRT YELLOW L 1
SHIRTD SHIRT GREEN XL 1
SHIRTE SHIRT YELLOW 2L 1

Datagridview4 result Non Transposed and non editable from datagridview2 (From Datatable)

Codeproduct Productname Size Qty
SHIRTA SHIRT WHITE S 1
SHIRTB SHIRT BLACK M 1
SHIRTC SHIRT YELLOW L 1
SHIRTD SHIRT GREEN XL 1
SHIRTE SHIRT YELLOW 2L 1

Solution

  • Here is a VB version of my original post. The code that I got from code converters didn't work and I needed to change it a little. This VB version works as expected.

    Main classes

    These are the classes which implement the rotated data source from original list, with help of a custom type descriptor:

    Imports System
    Imports System.Collections.Generic
    Imports System.ComponentModel
    Imports System.Linq
    Public Class RotatedListDataSource(Of T)
        Inherits List(Of RotatedItem)
        Public ReadOnly Property List As List(Of T)
        Public Sub New(ByVal list As List(Of T))
            list = list
            Me.AddRange(GetType(T).GetProperties() _
              .Select(Function(p)
                          Return New RotatedItem(p.Name, list.Cast(Of Object)().ToArray(), p.PropertyType)
                      End Function))
        End Sub
    End Class
    
    Public Class RotatedItem
        Inherits CustomTypeDescriptor
        Public ReadOnly Property PropertyName As String
        Private data As Object()
        Public ReadOnly Property Type As Type
        Public Sub New(ByVal propertyName As String, ByVal data As Object(), ByVal type As Type)
            Me.PropertyName = propertyName
            Me.data = data
            Me.Type = type
        End Sub
        Public Overrides Function GetProperties() As PropertyDescriptorCollection
            Return Me.GetProperties(New Attribute() {})
        End Function
        Public Overrides Function GetProperties(ByVal attributes As Attribute()) As PropertyDescriptorCollection
            Dim properties = New List(Of PropertyDescriptor)()
            properties.Add(New PropertyNameProperty(New Attribute() {New BrowsableAttribute(False)}))
    
            For i As Integer = 0 To data.Length - 1
                properties.Add(New IndexProperty(i, GetType(Object), New Attribute() {}))
            Next
    
            Return New PropertyDescriptorCollection(properties.ToArray())
        End Function
        Default Public Property Item(ByVal i As Integer) As Object
            Get
                Return data(i).GetType().GetProperty(PropertyName).GetValue(data(i))
            End Get
            Set(ByVal value As Object)
                data(i).GetType().GetProperty(PropertyName).SetValue(data(i), Convert.ChangeType(value, Type))
            End Set
        End Property
    End Class
    
    Public Class IndexProperty
        Inherits PropertyDescriptor
        Private index As Integer
        Private type As Type
        Public Sub New(ByVal index As Integer, ByVal type As Type, ByVal attributes As Attribute())
            MyBase.New(index.ToString(), attributes)
            Me.index = index
            Me.type = type
        End Sub
        Public Overrides ReadOnly Property ComponentType As Type
            Get
                Return GetType(RotatedItem)
            End Get
        End Property
        Public Overrides ReadOnly Property IsReadOnly As Boolean
            Get
                Return False
            End Get
        End Property
        Public Overrides ReadOnly Property PropertyType As Type
            Get
                Return type
            End Get
        End Property
        Public Overrides Function CanResetValue(ByVal component As Object) As Boolean
            Return False
        End Function
        Public Overrides Function GetValue(ByVal component As Object) As Object
            Return (CType(component, RotatedItem))(index)
        End Function
        Public Overrides Sub ResetValue(ByVal component As Object)
        End Sub
        Public Overrides Sub SetValue(ByVal component As Object, ByVal value As Object)
            CType(component, RotatedItem)(index) = value
        End Sub
        Public Overrides Function ShouldSerializeValue(ByVal component As Object) As Boolean
            Return True
        End Function
    End Class
    
    Public Class PropertyNameProperty
        Inherits PropertyDescriptor
        Public Sub New(ByVal attributes As Attribute())
            MyBase.New(NameOf(RotatedItem.PropertyName), attributes)
        End Sub
        Public Overrides ReadOnly Property ComponentType As Type
            Get
                Return GetType(RotatedItem)
            End Get
        End Property
        Public Overrides ReadOnly Property IsReadOnly As Boolean
            Get
                Return True
            End Get
        End Property
        Public Overrides ReadOnly Property PropertyType As Type
            Get
                Return GetType(String)
            End Get
        End Property
        Public Overrides Function CanResetValue(ByVal component As Object) As Boolean
            Return False
        End Function
        Public Overrides Function GetValue(ByVal component As Object) 
            Return (CType(component, RotatedItem)).PropertyName
        End Function
        Public Overrides Sub ResetValue(ByVal component As Object)
        End Sub
        Public Overrides Sub SetValue(ByVal component As Object, ByVal value As Object)
        End Sub
        Public Overrides Function ShouldSerializeValue(ByVal component As Object) As Boolean
            Return True
        End Function
    End Class
    

    Employee class

    This is the Employee class which is used in the example usage of the rotated data source

    Public Class Employee
        Public Property Id As Integer
        Public Property Name As String
        Public Property City As String
    End Class
    

    Example

    The following example shows how you can show a rotated list (transposed list) in a DataGridView:

    Imports System.ComponentModel
    Public Class Form1
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            'Data
            Dim list As New List(Of Employee) From
            {
                New Employee With {.Id = 1, .Name = "John", .City = "New York"},
                New Employee With {.Id = 2, .Name = "Steve", .City = "London"},
                New Employee With {.Id = 3, .Name = "Lucas", .City = "Paris"}
            }
    
            'Set Data Source of the DataGridView
            DGV.DataSource = New RotatedListDataSource(Of Employee)(list)
    
            'Hide Column Headers
            DGV.ColumnHeadersVisible = False
    
            'Set Row Headers Autosize
            DGV.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders
    
            'Show PropertyName on RowHeader
            AddHandler DGV.RowPrePaint,
                Sub(o, a)
                    Dim value = CType(DGV.Rows(a.RowIndex).DataBoundItem, RotatedItem).PropertyName
                    If a.RowIndex > -1 And $"{DGV.Rows(a.RowIndex).HeaderCell.Value}" <> value Then
                        DGV.Rows(a.RowIndex).HeaderCell.Value = value
                    End If
                End Sub
        End Sub
    End Class