datagridview access row when added without the need to loop through rows

Samir Ibrahim 1 Reputation point
2021-01-19T08:45:57.767+00:00

I have a datagridview to represent journal voucher debit/credit binded to bindingsource

when I code Me.dgv_jv.DataSource = bs_jv the dgv is populated with data

while the dgv is populated, I want to check a table field "DBCR" if equal CR then I want to add 8 spaces to ACC_NAME (I know how to do that)

I tried the code below, but it seems it execute this sub 4 times although I have 2 row

    Private Sub dgv_jv_RowsAdded(sender As Object, e As DataGridViewRowsAddedEventArgs) Handles dgv_jv.RowsAdded            
            MsgBox("e.RowIndex = " + e.RowIndex.ToString + vbCrLf + "dgv_jv.RowCount = " + dgv_jv.RowCount.ToString)                                        
    End Sub

I can create a variable to make this sub executed once, or i can loop through rows and do my changes

is there a datagridview event that will catch rows insert only once?

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

2 answers

Sort by: Most helpful
  1. Viorel 112.7K Reputation points
    2021-01-19T10:00:35.403+00:00

    If you want to add the spaces for formatting purposes, I think that you can consider the CellFormatting event. See how ShortFormDateFormat was used to display a custom value: https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.datagridview.cellformatting.

    0 comments No comments

  2. Karen Payne MVP 35,196 Reputation points
    2021-01-19T13:08:25.04+00:00

    Hello,

    One way to achieve this is to setup the DataGridView with a DataSource using a BindingList and BindingSource and subscribe to DataSourceChanged event of the BindingSource.

    Full source

    https://github.com/karenpayneoregon/visual-basic-getting-started/tree/master/BindingList_ListChanged_1

    In the example below the following class represents the container for displaying, adding, editing and deleting in the DataGridView. Note INotifyPropertyChanged provides the ability for the DataGridView to be notified of changes and reflect this visually. The code in Person class may seem like a lot but it's worth the effort.

    58135-11111111111.png

    Container

    Imports System.ComponentModel  
    Imports System.Runtime.CompilerServices  
      
    Public Class Person  
        Implements INotifyPropertyChanged  
      
        Private _firstName As String  
        Private _lastName As String  
        Private _personId As Integer  
      
        Public Property PersonId() As Integer  
            Get  
                Return _personId  
            End Get  
            Set  
                _personId = Value  
                OnPropertyChanged()  
            End Set  
        End Property  
      
        Public Property FirstName() As String  
            Get  
                Return _firstName  
            End Get  
            Set  
                _firstName = Value  
                OnPropertyChanged()  
            End Set  
        End Property  
      
        Public Property LastName() As String  
            Get  
                Return _lastName  
            End Get  
            Set  
                _lastName = Value  
                OnPropertyChanged()  
            End Set  
        End Property  
        Public Event PropertyChanged As PropertyChangedEventHandler _  
            Implements INotifyPropertyChanged.PropertyChanged  
      
        Protected Overridable Sub OnPropertyChanged(  
            <CallerMemberName> Optional memberName As String = Nothing)  
      
            RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(memberName))  
      
        End Sub  
      
        Public Overrides Function ToString() As String  
            Return $"{PersonId} {FirstName} {LastName}"  
        End Function  
    End Class  
    

    Load

    Here I use mocked data

    Public Class DataOperations  
      
        Public Shared Function LoadPeople() As List(Of Person)  
            Return New List(Of Person) From {  
                New Person() With {.PersonId = 1, .FirstName = "Karen", .LastName = "Payne"},  
                New Person() With {.PersonId = 2, .FirstName = "Bill", .LastName = "Miller"},  
                New Person() With {.PersonId = 3, .FirstName = "Anne", .LastName = "Adams"}}  
        End Function  
    End Class  
      
    

    Form code

    Here DataSourceChanged is fired when personBindList = New BindingList(Of Person)(peopleList) is called. I check for FirstName equal to Karen and change it.

    Imports System.ComponentModel  
      
    Public Class Form1  
        Private personBindList As New BindingList(Of Person)  
        WithEvents personBindingSource As New BindingSource  
      
        Private Sub Form1_Shown(sender As Object, e As EventArgs) Handles Me.Shown  
            PeopleDataGridView.AutoGenerateColumns = False  
      
            Dim peopleList = DataOperations.LoadPeople()  
      
            personBindList = New BindingList(Of Person)(peopleList)  
      
            personBindingSource.DataSource = personBindList  
            PeopleDataGridView.DataSource = personBindingSource  
      
        End Sub  
      
        Private Sub personBindingSource_DataSourceChanged(sender As Object, e As EventArgs) _  
            Handles personBindingSource.DataSourceChanged  
      
            For index As Integer = 0 To personBindList.Count - 1  
                If personBindList(index).FirstName = "Karen" Then  
                    personBindList(index).FirstName = "Karen 1"  
                End If  
            Next  
      
        End Sub  
    End Class  
      
    

    In closing

    If you are using a DataTable as the DataSource for the BindingSource the above will still work without the Person class as DataSourceChanged event will still be triggered.

    0 comments No comments