Bind or show object properties values in datagridview rows?

Hobbyist_programmer 621 Reputation points
2020-12-04T22:55:45.677+00:00

Hallo I am looking for a way to bind object properties to data grid view row items . for example i have sample class like blow

Public Class Sample

Public Readonly Property Prop1 as integer
Public Readonly Property Prop2 as integer

End Class 

and a datagridview with 3 columns which shows the description and value of the Prop1 and Prop2 and may be i can hide the property column

Property Description Value
Prop1 Description 1 xx
Prop2 Description 2 xx

Is there a way to do this so that the properties values are always synced/changes immediately? Thanks.

VB
VB
An object-oriented programming language developed by Microsoft that is implemented on the .NET Framework. Previously known as Visual Basic .NET.
2,568 questions
0 comments No comments
{count} votes

Accepted answer
  1. Peter Fleischer (former MVP) 19,231 Reputation points
    2020-12-05T19:43:25.8+00:00

    Hi,
    you can use Reflection to get names and values of properties for displaying in Datagrid like in following demo:

    Imports System.Reflection
    
    Public Class Form10
    
      Private dgv As New DataGridView With {.Dock = DockStyle.Fill, .AutoGenerateColumns = True}
    
      Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Me.Controls.Add(dgv)
        '
        Dim s As New Sample
        '
        dgv.DataSource = New PropertyList(s)
      End Sub
    
      Private Class PropertyList
        Inherits List(Of PropertyItem)
        Public Sub New(obj As Object)
          For Each prop In obj.GetType().GetProperties(BindingFlags.Public Or BindingFlags.Instance)
            Me.Add(New PropertyItem(obj, prop))
          Next
        End Sub
      End Class
    
      Public Class PropertyItem
        Public Sub New(obj As Object, prop As PropertyInfo)
          Me._obj = obj
          Me._prop = prop
        End Sub
        Private _obj As Object
        Private _prop As PropertyInfo
        Public ReadOnly Property PropertyName As String
          Get
            Return Me._prop.Name
          End Get
        End Property
        Public ReadOnly Property PropertyValue As Object
          Get
            Return Me._prop.GetValue(Me._obj)
          End Get
        End Property
      End Class
    
      Public Class Sample
        Public ReadOnly Property Prop1 As Integer = 1
        Public ReadOnly Property Prop2 As Integer = 2
      End Class
    
    End Class
    
    0 comments No comments

5 additional answers

Sort by: Most helpful
  1. Anonymous
    2020-12-04T23:44:03.677+00:00

    Hi
    If I understand your question, maybe this is helpful. A stand alone example. Adds a few initial values and then Button1 click adds random pair each click (and everything is 'sync'ed')

    ' FORM1 with
    ' DataGridView1,
    ' Button1
    Option Strict On
    Option Explicit On
    Public Class Form1
        Dim col As New List(Of Sample)
        Dim BS As New BindingSource
        Dim rand As New Random
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            col.Add(New Sample(1, 2))
            col.Add(New Sample(11, 21))
            col.Add(New Sample(21, 22))
    
            BS.DataSource = col
            DataGridView1.DataSource = BS
        End Sub
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            col.Add(New Sample(rand.Next(99, 999), rand.Next(999, 9999)))
            BS.ResetBindings(False)
        End Sub
        Public Class Sample
            Public ReadOnly Property Prop1 As Integer
            Public ReadOnly Property Prop2 As Integer
            Sub New(one As Integer, two As Integer)
                Prop1 = one
                Prop2 = two
            End Sub
        End Class
    End Class
    

  2. Peter Fleischer (former MVP) 19,231 Reputation points
    2020-12-05T09:16:43.607+00:00

    Hi,
    you can use PropertyGrid to display and change values of properties of object. Try following demo:

    Public Class Form09
    
      Private pg As New PropertyGrid With {.Dock = DockStyle.Fill,
        .Text = "Property Grid", .CommandsVisibleIfAvailable = True}
      Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Me.Controls.Add(pg)
        ' '
        Dim s As New Sample
        ' '
        pg.SelectedObject = s
      End Sub
    
      Public Class Sample
        Public ReadOnly Property Prop1 As Integer = 1
        Public ReadOnly Property Prop2 As Integer = 2
      End Class
    
    End Class
    

  3. Karen Payne MVP 35,031 Reputation points
    2020-12-05T10:39:18.847+00:00

    Hello @Hobbyist_programmer

    For your requirements, implement INotifyPropertyChanged Interface for allowing immediate updates to the user interface. If we were to simply set the list (in this case of Person) to the DataGridView it would seem we are done although there is no sorting so a custom BindingList (found here) is needed and on top of this a BindingSource to tie things together.

    You can copy code below or copy the full code including the custom BindingList from the following GitHub repository.

    Here is the Person class which implements INotifyPropertyChanged.

    Imports System.ComponentModel  
    Imports System.Runtime.CompilerServices  
      
    Public Class Person  
        Implements INotifyPropertyChanged  
      
        Public Property Id() As Integer  
        Public Property FirstName() As String  
        Public Property LastName() As String  
      
        Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged  
        Protected Overridable Sub OnPropertyChanged(<CallerMemberName> Optional ByVal propertyName As String = Nothing)  
            PropertyChangedEvent?.Invoke(Me, New PropertyChangedEventArgs(propertyName))  
        End Sub  
    End Class  
    

    And a class for some mocked up data.

    Public Class Mocked  
        Public Shared ReadOnly Property PeopleList() As List(Of Person)  
            Get  
                Return New List(Of Person) From {  
                    New Person() With {.Id = 1, .FirstName = "Karen", .LastName = "Payne"},  
                    New Person() With {.Id = 2, .FirstName = "Bill", .LastName = "Smith"},  
                    New Person() With {.Id = 3, .FirstName = "Mary", .LastName = "Jones"},  
                    New Person() With {.Id = 4, .FirstName = "Kim", .LastName = "Adams"}}  
            End Get  
        End Property  
    End Class  
    

    Form code for displaying, minimal editing and a mocked up add new Person.

    Public Class Form1  
      
        Private peopleBindingList As SortableBindingList(Of Person)  
        Private peopleBindingSource As New BindingSource()  
      
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load  
            peopleBindingList = New SortableBindingList(Of Person)(Mocked.PeopleList)  
            peopleBindingSource.DataSource = peopleBindingList  
      
            dataGridView1.DataSource = peopleBindingSource  
            dataGridView1.Columns("id").Visible = False  
        End Sub  
      
        Private Sub CurrentPersonButton_Click(sender As Object, e As EventArgs) _  
            Handles CurrentPersonButton.Click  
      
            If peopleBindingSource.Current Is Nothing Then  
                Return  
            End If  
      
            Dim currentPerson = peopleBindingList(peopleBindingSource.Position)  
            MessageBox.Show($"{currentPerson.Id}, {currentPerson.FirstName}, {currentPerson.LastName}")  
      
        End Sub  
      
        Private Sub NewPersonButton_Click(sender As Object, e As EventArgs) Handles NewPersonButton.Click  
      
            peopleBindingList.Add(New Person() With  
                {  
                    .Id = peopleBindingList.Select(Function(p) p.Id).Max() + 1,  
                    .FirstName = "Jude",  
                    .LastName = "Lennon"  
                })  
      
        End Sub  
    End Class  
    

    Screen shot

    45355-1111.png


  4. Karen Payne MVP 35,031 Reputation points
    2020-12-05T22:14:37.66+00:00

    @Hobbyist_programmer

    DataGridView columns are created in the designer, nothing special other than the first column is read-only. I use reflection to set cell values from properties. Since I didn't want to disturb first code sample I left the Id property in and filtered it out for the PropertyInfo code in form load.

    Imports System.Reflection  
    Public Class Form2  
        Private peopleBindingSource As New BindingSource()  
        Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load  
      
            Dim person = New Person() With {.Id = 1, .FirstName = "Karen", .LastName = "Payne"}  
      
            peopleBindingSource.DataSource = New List(Of Person) From {person}  
      
            Dim properties = GetType(Person).  
                    GetProperties().  
                    Where(  
                        Function(propertyInfo)  
                            Return propertyInfo.PropertyType IsNot GetType(Integer)  
                        End Function)  
      
            For Each propertyInfo As PropertyInfo In properties  
                DataGridView1.Rows.Add(propertyInfo.Name,  
                                       propertyInfo.GetValue(person),  
                                       propertyInfo.Name)  
            Next  
      
            AddHandler DataGridView1.CellValueChanged, AddressOf CellChanged  
        End Sub  
        Private Sub CellChanged(sender As Object, e As DataGridViewCellEventArgs)  
            Dim item = CType(peopleBindingSource.Current, Person)  
      
            If e.RowIndex = 0 Then  
                item.FirstName = DataGridView1.Rows(e.RowIndex).Cells(1).Value.ToString()  
            Else  
                item.LastName = DataGridView1.Rows(e.RowIndex).Cells(1).Value.ToString()  
            End If  
      
        End Sub  
        Private Sub PersonValues_Click(sender As Object, e As EventArgs) Handles Button1.Click  
            Dim person = CType(peopleBindingSource.Current, Person)  
      
            MessageBox.Show($"{person.FirstName} {person.LastName}")  
      
        End Sub  
    End Class  
    

    45290-b1.png

    0 comments No comments