Answered by:
Display objects from different classes in same DataGridView

Question
-
Hallo,
How can i display collection of objects from different classes in one datagridview. Classes have similar properties but they can have different number of properties.
Thanks
Sunday, November 22, 2020 7:59 PM
Answers
-
Hi Shan,
you can use one collection with different data objects and DataGridView in virtual mode. Try following demo:Public Class Form1 Private WithEvents dgv As New DataGridView With {.AutoGenerateColumns = False, .VirtualMode = True, .Dock = DockStyle.Fill, .AllowUserToAddRows = False} Private col As New List(Of Object) Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load LoadData() Me.Controls.Add(dgv) dgv.RowCount = col.Count dgv.ColumnCount = 3 End Sub Private Sub LoadData() col.Add(New Data1 With {.ID = 1, .Value1 = "Row 1 Data1"}) col.Add(New Data2 With {.ID = 2, .Value2 = "Row 1 Data2", .Value3 = "Value 3 Row 1 Data2"}) col.Add(New Data1 With {.ID = 3, .Value1 = "Row 2 Data1"}) col.Add(New Data2 With {.ID = 4, .Value2 = "Row 2 Data2", .Value3 = "Value 3 Row 2 Data2"}) End Sub Private Sub dgv_CellValueNeeded(sender As Object, e As DataGridViewCellValueEventArgs) Handles dgv.CellValueNeeded Dim d1 = TryCast(col(e.RowIndex), Data1) If d1 IsNot Nothing Then Select Case e.ColumnIndex Case 0 e.Value = d1.ID.ToString Case 1 e.Value = d1.Value1 Case Else e.Value = String.Empty End Select Exit Sub End If Dim d2 = TryCast(col(e.RowIndex), Data2) If d2 IsNot Nothing Then Select Case e.ColumnIndex Case 0 e.Value = d2.ID.ToString Case 1 e.Value = d2.Value2 Case 2 e.Value = d2.Value3 Case Else e.Value = String.Empty End Select Exit Sub End If End Sub Public Class Data1 Public Property ID As Integer Public Property Value1 As String End Class Public Class Data2 Public Property ID As Integer Public Property Value2 As String Public Property Value3 As String End Class End Class
--
Best Regards / Viele Grüße
Peter Fleischer (former MVP for Developer Technologies)
Homepage, Tipps, Tricks- Proposed as answer by KHURRAM RAHIM Friday, November 27, 2020 11:03 AM
- Marked as answer by Shan1986 Friday, November 27, 2020 2:25 PM
- Edited by Peter Fleischer Friday, November 27, 2020 5:18 PM
Monday, November 23, 2020 8:43 PM -
Hi Shan1986,
Thanks for your feedback.
>>I was thinking whether it would be possible to make just two columns in the datagrid view
Since this thread is related to the other one, you can refer to the following code which is based on the 'Category' attribute to make two columns in the datagridview.
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click Dim lst1 As List(Of String) = GetAllAttributes(GetType(Category1)) Dim lst2 As List(Of String) = GetAllAttributes(GetType(Category2)) Dim unionLst As List(Of String) = lst1.Union(lst2).ToList() Dim table As DataTable = GenerateTableFromLst(unionLst, "WeightCategories") table.Columns.Add("Weight", GetType(System.Int32), "'0'") DataGridView1.DataSource = table End Sub Private Function GetAllAttributes(ByVal type As Type) As List(Of String) Dim lstAttr As List(Of String) = New List(Of String)() For Each prop In type.GetProperties() Dim category = CType(prop.GetCustomAttributes(GetType(Category), False).FirstOrDefault(), Category) If Not lstAttr.Contains(category.weightCategory) Then lstAttr.Add(category.weightCategory) End If Next Return lstAttr End Function Private Function GenerateTableFromLst(ByVal lst As List(Of String), ByVal columnName As String) As DataTable Dim dt As DataTable = New DataTable() dt.Columns.Add(columnName) For Each str As String In lst Dim drow As DataRow = dt.NewRow() drow(columnName) = str dt.Rows.Add(drow) Next Return dt End Function
Result of my test.
Hope it could be helpful.
Best Regards,
Xingyu Zhao
Visual Basic and CLR forum will be migrating to a new home on Microsoft Q&A! (VB.NET and CLR) We invite you to post new questions in the new home on Microsoft Q&A ! For more information, please refer to the sticky post(VB.NET and CLR).
- Proposed as answer by KHURRAM RAHIM Friday, November 27, 2020 6:50 AM
- Marked as answer by Shan1986 Friday, November 27, 2020 2:25 PM
Friday, November 27, 2020 2:20 AM
All replies
-
Hi Shan,
yes, you can.If your application ist Windows Forms application use virtual mode.
If your application ist WPF application use template.
--
Best Regards / Viele Grüße
Peter Fleischer (former MVP for Developer Technologies)
Homepage, Tipps, TricksSunday, November 22, 2020 10:03 PM -
If homonymous properties have the same type, then maybe use something like ‘list1.Cast<object>().Concat(list2.Cast<object>()).Concat(…)’ to make a single collection of objects, and assign it to dataGridView.DataSource. Probably you should add the columns explicitly instead of specifying AutoGenerateColumns.
Show some details about your data.
Monday, November 23, 2020 1:00 AM -
if i understand correctly, i have to make a single collection first and then bind to datagridview?Monday, November 23, 2020 7:59 AM
-
Hi Shan,
you can use one collection with different data objects and DataGridView in virtual mode. Try following demo:Public Class Form1 Private WithEvents dgv As New DataGridView With {.AutoGenerateColumns = False, .VirtualMode = True, .Dock = DockStyle.Fill, .AllowUserToAddRows = False} Private col As New List(Of Object) Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load LoadData() Me.Controls.Add(dgv) dgv.RowCount = col.Count dgv.ColumnCount = 3 End Sub Private Sub LoadData() col.Add(New Data1 With {.ID = 1, .Value1 = "Row 1 Data1"}) col.Add(New Data2 With {.ID = 2, .Value2 = "Row 1 Data2", .Value3 = "Value 3 Row 1 Data2"}) col.Add(New Data1 With {.ID = 3, .Value1 = "Row 2 Data1"}) col.Add(New Data2 With {.ID = 4, .Value2 = "Row 2 Data2", .Value3 = "Value 3 Row 2 Data2"}) End Sub Private Sub dgv_CellValueNeeded(sender As Object, e As DataGridViewCellValueEventArgs) Handles dgv.CellValueNeeded Dim d1 = TryCast(col(e.RowIndex), Data1) If d1 IsNot Nothing Then Select Case e.ColumnIndex Case 0 e.Value = d1.ID.ToString Case 1 e.Value = d1.Value1 Case Else e.Value = String.Empty End Select Exit Sub End If Dim d2 = TryCast(col(e.RowIndex), Data2) If d2 IsNot Nothing Then Select Case e.ColumnIndex Case 0 e.Value = d2.ID.ToString Case 1 e.Value = d2.Value2 Case 2 e.Value = d2.Value3 Case Else e.Value = String.Empty End Select Exit Sub End If End Sub Public Class Data1 Public Property ID As Integer Public Property Value1 As String End Class Public Class Data2 Public Property ID As Integer Public Property Value2 As String Public Property Value3 As String End Class End Class
--
Best Regards / Viele Grüße
Peter Fleischer (former MVP for Developer Technologies)
Homepage, Tipps, Tricks- Proposed as answer by KHURRAM RAHIM Friday, November 27, 2020 11:03 AM
- Marked as answer by Shan1986 Friday, November 27, 2020 2:25 PM
- Edited by Peter Fleischer Friday, November 27, 2020 5:18 PM
Monday, November 23, 2020 8:43 PM -
Hi Shan,
you can use one collection with different data objects ans DataGridView in virtual mode. Try following demo:Public Class Form1 Private WithEvents dgv As New DataGridView With {.AutoGenerateColumns = False, .VirtualMode = True, .Dock = DockStyle.Fill, .AllowUserToAddRows = False} Private col As New List(Of Object) Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load LoadData() Me.Controls.Add(dgv) dgv.RowCount = col.Count dgv.ColumnCount = 3 End Sub Private Sub LoadData() col.Add(New Data1 With {.ID = 1, .Value1 = "Row 1 Data1"}) col.Add(New Data2 With {.ID = 2, .Value2 = "Row 1 Data2", .Value3 = "Value 3 Row 1 Data2"}) col.Add(New Data1 With {.ID = 3, .Value1 = "Row 2 Data1"}) col.Add(New Data2 With {.ID = 4, .Value2 = "Row 2 Data2", .Value3 = "Value 3 Row 2 Data2"}) End Sub Private Sub dgv_CellValueNeeded(sender As Object, e As DataGridViewCellValueEventArgs) Handles dgv.CellValueNeeded Dim d1 = TryCast(col(e.RowIndex), Data1) If d1 IsNot Nothing Then Select Case e.ColumnIndex Case 0 e.Value = d1.ID.ToString Case 1 e.Value = d1.Value1 Case Else e.Value = String.Empty End Select Exit Sub End If Dim d2 = TryCast(col(e.RowIndex), Data2) If d2 IsNot Nothing Then Select Case e.ColumnIndex Case 0 e.Value = d2.ID.ToString Case 1 e.Value = d2.Value2 Case 2 e.Value = d2.Value3 Case Else e.Value = String.Empty End Select Exit Sub End If End Sub Public Class Data1 Public Property ID As Integer Public Property Value1 As String End Class Public Class Data2 Public Property ID As Integer Public Property Value2 As String Public Property Value3 As String End Class End Class
--
Best Regards / Viele Grüße
Peter Fleischer (former MVP for Developer Technologies)
Homepage, Tipps, TricksTuesday, November 24, 2020 11:41 AM -
Hi Shan,
instead of binding my demo show how to display different data objects in one collection using virtual mode.--
Best Regards / Viele Grüße
Peter Fleischer (former MVP for Developer Technologies)
Homepage, Tipps, TricksTuesday, November 24, 2020 5:02 PM -
Hi Shan,
tried.i cant bind.
instead of binding my demo show how to display different data objects in one collection using virtual mode.
--
Best Regards / Viele Grüße
Peter Fleischer (former MVP for Developer Technologies)
Homepage, Tipps, TricksTuesday, November 24, 2020 7:47 PM -
Hi Shan1986,
I have some questions to confirm with you based on your description.
>>Classes have similar properties but they can have different number of properties.
Are these classes related to the classes shown in your other thread?
How do you want to bind classes to DataGridView? Could you provide more details or an example here?
Best Regards,
Xingyu Zhao
Visual Basic and CLR forum will be migrating to a new home on Microsoft Q&A! (VB.NET and CLR) We invite you to post new questions in the new home on Microsoft Q&A ! For more information, please refer to the sticky post(VB.NET and CLR).
Wednesday, November 25, 2020 7:29 AM -
Hallo Xingyu, yes. How to bind i have no idea but i used to bind the collection with bindinglist , bindingsource. I am open to all ideas.Wednesday, November 25, 2020 9:34 AM
-
Hi Shan,
via data binding (DataGridView.DataSource) you cannot use different data objects (different properties). In this case you can use only virtual mode like in my demo.
--
Best Regards / Viele Grüße
Peter Fleischer (former MVP for Developer Technologies)
Homepage, Tipps, Tricks- Edited by Peter Fleischer Friday, November 27, 2020 5:18 PM
Wednesday, November 25, 2020 9:53 AM -
Hi Shan,
via data binding (DataGridView.DataSource) you cannot use different data objects (different properties). In this case you can use only virtual mode like in may demo.
--
Best Regards / Viele Grüße
Peter Fleischer (former MVP for Developer Technologies)
Homepage, Tipps, TricksThanks peter. I was thinking whether it would be possible to make just two columns in the datagrid view , one column lists all the properties from the classes and another column display its values may be sum of values of all instances.
Is it possible ? that should be also fine.
Thursday, November 26, 2020 7:25 AM -
Hi Shan1986,
Thanks for your feedback.
>>I was thinking whether it would be possible to make just two columns in the datagrid view
Since this thread is related to the other one, you can refer to the following code which is based on the 'Category' attribute to make two columns in the datagridview.
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click Dim lst1 As List(Of String) = GetAllAttributes(GetType(Category1)) Dim lst2 As List(Of String) = GetAllAttributes(GetType(Category2)) Dim unionLst As List(Of String) = lst1.Union(lst2).ToList() Dim table As DataTable = GenerateTableFromLst(unionLst, "WeightCategories") table.Columns.Add("Weight", GetType(System.Int32), "'0'") DataGridView1.DataSource = table End Sub Private Function GetAllAttributes(ByVal type As Type) As List(Of String) Dim lstAttr As List(Of String) = New List(Of String)() For Each prop In type.GetProperties() Dim category = CType(prop.GetCustomAttributes(GetType(Category), False).FirstOrDefault(), Category) If Not lstAttr.Contains(category.weightCategory) Then lstAttr.Add(category.weightCategory) End If Next Return lstAttr End Function Private Function GenerateTableFromLst(ByVal lst As List(Of String), ByVal columnName As String) As DataTable Dim dt As DataTable = New DataTable() dt.Columns.Add(columnName) For Each str As String In lst Dim drow As DataRow = dt.NewRow() drow(columnName) = str dt.Rows.Add(drow) Next Return dt End Function
Result of my test.
Hope it could be helpful.
Best Regards,
Xingyu Zhao
Visual Basic and CLR forum will be migrating to a new home on Microsoft Q&A! (VB.NET and CLR) We invite you to post new questions in the new home on Microsoft Q&A ! For more information, please refer to the sticky post(VB.NET and CLR).
- Proposed as answer by KHURRAM RAHIM Friday, November 27, 2020 6:50 AM
- Marked as answer by Shan1986 Friday, November 27, 2020 2:25 PM
Friday, November 27, 2020 2:20 AM -
Hi Shan1986,
Thanks for your feedback.
>>I was thinking whether it would be possible to make just two columns in the datagrid view
Since this thread is related to the other one, you can refer to the following code which is based on the 'Category' attribute to make two columns in the datagridview.
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click Dim lst1 As List(Of String) = GetAllAttributes(GetType(Category1)) Dim lst2 As List(Of String) = GetAllAttributes(GetType(Category2)) Dim unionLst As List(Of String) = lst1.Union(lst2).ToList() Dim table As DataTable = GenerateTableFromLst(unionLst, "WeightCategories") table.Columns.Add("Weight", GetType(System.Int32), "'0'") DataGridView1.DataSource = table End Sub Private Function GetAllAttributes(ByVal type As Type) As List(Of String) Dim lstAttr As List(Of String) = New List(Of String)() For Each prop In type.GetProperties() Dim category = CType(prop.GetCustomAttributes(GetType(Category), False).FirstOrDefault(), Category) If Not lstAttr.Contains(category.weightCategory) Then lstAttr.Add(category.weightCategory) End If Next Return lstAttr End Function Private Function GenerateTableFromLst(ByVal lst As List(Of String), ByVal columnName As String) As DataTable Dim dt As DataTable = New DataTable() dt.Columns.Add(columnName) For Each str As String In lst Dim drow As DataRow = dt.NewRow() drow(columnName) = str dt.Rows.Add(drow) Next Return dt End Function
Result of my test.
Hope it could be helpful.
Best Regards,
Xingyu Zhao
Visual Basic and CLR forum will be migrating to a new home on Microsoft Q&A! (VB.NET and CLR) We invite you to post new questions in the new home on Microsoft Q&A ! For more information, please refer to the sticky post(VB.NET and CLR).
Friday, November 27, 2020 3:04 PM