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