Link to home
Start Free TrialLog in
Avatar of gem56
gem56

asked on

Problem implementing data binding with DataGridView

Hi guys,
I thought I had this issue covered but it seems not. I have a data bound DataGridView to a IList (Of T) collection. I can make changes to data (either in DataGridView or the object programatically) but I can't work ot how to insert/delete rows/objects programatically. If I remove an object the DataGridView gives me erors as it has an extra row and if I delete a DataGridView row first then I get objct index errors.
My understanding is that providing I implement IList (of T) interface then my collection and DataGridView should be able to synchronise automatially.

To help me resolve the problem I went back to a (very simple) sample that I used in he past with the aim of getting the mechanism working and then I would just simply adjust my project code accordingly.

Below is the whole code of my sample. If you want to run the sample just create a Form with a DataGridView called (grdCustomers) and two command buttons (btnAddRow and btnDeleteRow), that I used to Add and Delete a row.

ANy assistance would be much appreciated.

/Michael

'------------------------------------------------------------------------------------------------
Imports System.ComponentModel           ' Needed for using <Bindable(True)>


Public Class frmCustomers

    Dim Customers As New CustomersList

    Private Sub frmCustomers_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        MyTrace("+frmCust:LoadCustomers")
        Try
            AddHandler Customers.MyTrace, AddressOf MyTrace
            Dim l As IList = CType(Customers, IList)
            l.Add(ReadCustomer(1))
            l.Add(ReadCustomer(2))
            l.Add(ReadCustomer(3))
            l.Add(ReadCustomer(4))
            Me.grdCustomers.DataSource = Customers
            Me.grdCustomers.Refresh()
            MyTrace("-frmCust:LoadCustomers")
        Catch ex As Exception
            MsgBox("Error in '" & Mid(ex.StackTrace, InStrRev(ex.StackTrace, "\") + 1) & "' - " & ex.Message, MsgBoxStyle.Exclamation)
        End Try
    End Sub

    Private Function ReadCustomer(ByVal n As Int16) As Customer
        MyTrace("+CList:ReadCustomer")
        Dim cust As New Customer(Customers)
        cust.FirstName = "First" & n
        cust.LastName = "Last" & n
        MyTrace("-CList:ReadCustomer`")
        Return cust
    End Function

    Private Sub MyTrace(ByVal Mess As String)
        Static iLevel As Int16
        If Mid(Mess, 1, 1) = "+" Then
            Debug.Print(Space(iLevel * 4) & Replace(Mess, "+", "--->", 1, 1))
            iLevel += 1
        ElseIf Mid(Mess, 1, 1) = "-" Then
            iLevel -= 1
            Debug.Print(Space(iLevel * 4) & Replace(Mess, "-", "<---", 1, 1))
        Else
            Debug.Print(Space(iLevel * 4) & Replace(Mess, "=", "    ", 1, 1))
        End If
    End Sub

    Private Sub btnAddRow_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAddRow.Click
        Me.MyTrace("+frm:btnAddNewCustomer_Click")
        Dim cust As New Customer(Me.Customers)
        cust.FirstName = "First1"
        cust.LastName = "Last1"
        Me.Customers.Add(cust)
        MyTrace("-frm:btnAddNewCustomer_Click")
    End Sub

    Private Sub btnDeleteRow_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnDeleteRow.Click
        Me.MyTrace("+frm:btnDeleteRow_Click")
        Me.Customers.RemoveAt(Me.grdCustomers.CurrentRow.Index)
        Me.grdCustomers.Rows.RemoveAt(Me.grdCustomers.CurrentRow.Index)
        MyTrace("-frm:btnDeleteRow_Click")
    End Sub

End Class



Public Class Customer
    Implements IEditableObject
    Public Event TraceMe(ByVal Mess As String)

    Structure CustomerData
        Friend firstName As String
        Friend lastName As String
    End Structure

    Public parent As CustomersList
    Private custData As CustomerData
    Private backupData As CustomerData
    Private inTxn As Boolean = False

    ' Implements IEditableObject
    Sub BeginEdit() Implements IEditableObject.BeginEdit
        _MyParent.MyTrace1("+Cust:BeginEdit")
        If Not inTxn Then
            Me.backupData = custData
            inTxn = True
        End If
        _MyParent.MyTrace1("-Cust:BeginEdit")
    End Sub

    Sub CancelEdit() Implements IEditableObject.CancelEdit
        _MyParent.MyTrace1("+CancelEdit")
        If inTxn Then
            Me.custData = backupData
            inTxn = False
        End If
        _MyParent.MyTrace1("-CancelEdit")
    End Sub

    Sub EndEdit() Implements IEditableObject.EndEdit
        _MyParent.MyTrace1("+EndEdit")
        If inTxn Then
            backupData = New CustomerData()
            inTxn = False
        End If
        _MyParent.MyTrace1("-EndEdit")
    End Sub

    Private _MyParent As CustomersList
    Public Sub New(ByVal objMyParent As CustomersList)
        _MyParent = objMyParent
        _MyParent.MyTrace1("+Cust:New")
        Me.custData = New CustomerData()
        Me.custData.firstName = ""
        Me.custData.lastName = ""
        _MyParent.MyTrace1("-Cust:New")
    End Sub

    Public Property FirstName() As String
        Get
            _MyParent.MyTrace1("=Cust:FirstName<--" & Me.custData.firstName)
            Return Me.custData.firstName
        End Get
        Set(ByVal Value As String)
            _MyParent.MyTrace1("=Cust:FirstName-->" & Value)
            Me.custData.firstName = Value
            Me.OnCustomerChanged()
        End Set
    End Property

    Public Property LastName() As String
        Get
            _MyParent.MyTrace1("=Cust:LastName<--" & Me.custData.lastName)
            Return Me.custData.lastName
        End Get
        Set(ByVal Value As String)
            _MyParent.MyTrace1("=Cust:LastName-->" & Value)
            Me.custData.lastName = Value
            Me.OnCustomerChanged()
        End Set
    End Property

    Friend Property Parents() As CustomersList
        Get
            _MyParent.MyTrace1("=Cust:Parents")
            Return parent
        End Get
        Set(ByVal Value As CustomersList)
            _MyParent.MyTrace1("=Cust:Parents")
            parent = Value
        End Set
    End Property

    Private Sub OnCustomerChanged()
        If Not inTxn And Not (parent Is Nothing) Then
            parent.CustomerChanged(Me)
        End If
    End Sub

    Public Overrides Function ToString() As String
        Dim sb As New IO.StringWriter()
        sb.Write(Me.FirstName)
        sb.Write(" ")
        sb.Write(Me.LastName)
        Return sb.ToString()
    End Function

End Class



Public Class CustomersList
    Inherits CollectionBase
    Implements IBindingList

    Public Event MyTrace(ByVal Mess As String)

    Private resetEvent As New ListChangedEventArgs(ListChangedType.Reset, -1)
    Private onListChanged1 As ListChangedEventHandler

    Default Public Property Item(ByVal index As Integer) As Customer
        Get
            RaiseEvent MyTrace("=CList:Item<--")
            Return CType(List(index), Customer)
        End Get
        Set(ByVal Value As Customer)
            RaiseEvent MyTrace("=CList:Item-->")
            List(index) = Value
        End Set
    End Property

    Public Function Add(ByVal value As Customer) As Integer
        RaiseEvent MyTrace("=CList:Add")
        Return List.Add(value)
    End Function

    Public Sub Remove(ByVal value As Customer)
        RaiseEvent MyTrace("+>CList:Remove")
        List.Remove(value)
        RaiseEvent MyTrace("-CList:Remove")
    End Sub

    Protected Overridable Sub OnListChanged(ByVal ev As ListChangedEventArgs)
        RaiseEvent MyTrace("+CList:OnListChanged")
        If Not (onListChanged1 Is Nothing) Then
            onListChanged1(Me, ev)
        End If
        RaiseEvent MyTrace("-CList:OnListChanged")
    End Sub

    Protected Overrides Sub OnClear()
        RaiseEvent MyTrace("+CList:OnClear")
        Dim c As Customer
        For Each c In List
            c.parent = Nothing
        Next c
        RaiseEvent MyTrace("-CList:OnClear")
    End Sub

    Protected Overrides Sub OnClearComplete()
        RaiseEvent MyTrace("+CList:OnClearComplete")
        OnListChanged(resetEvent)
        RaiseEvent MyTrace("-CList:OnClearComplete")
    End Sub

    Protected Overrides Sub OnInsertComplete(ByVal index As Integer, ByVal value As Object)
        RaiseEvent MyTrace("+CList:OnInsertComplete")
        Dim c As Customer = CType(value, Customer)
        c.parent = Me
        OnListChanged(New ListChangedEventArgs(ListChangedType.ItemAdded, index))
        RaiseEvent MyTrace("-CList:OnInsertComplete")
    End Sub

    Protected Overrides Sub OnRemoveComplete(ByVal index As Integer, ByVal value As Object)
        RaiseEvent MyTrace("+CList:OnRemoveComplete")
        Dim c As Customer = CType(value, Customer)
        c.parent = Me
        OnListChanged(New ListChangedEventArgs(ListChangedType.ItemDeleted, index))
        RaiseEvent MyTrace("-CList:OnRemoveComplete")
    End Sub

    Protected Overrides Sub OnSetComplete(ByVal index As Integer, ByVal oldValue As Object, ByVal newValue As Object)
        RaiseEvent MyTrace("+CList:OnSetComplete")
        If oldValue <> newValue Then
            Dim oldcust As Customer = CType(oldValue, Customer)
            Dim newcust As Customer = CType(newValue, Customer)
            oldcust.parent = Nothing
            newcust.parent = Me
            OnListChanged(New ListChangedEventArgs(ListChangedType.ItemAdded, index))
        End If
        RaiseEvent MyTrace("-CList:OnSetComplete")
    End Sub

    Friend Sub CustomerChanged(ByVal cust As Customer)
        RaiseEvent MyTrace("+CList:CustomerChanged")
        Dim index As Integer = List.IndexOf(cust)
        OnListChanged(New ListChangedEventArgs(ListChangedType.ItemChanged, index))
        RaiseEvent MyTrace("-CList:CustomerChanged")
    End Sub

    ' Implements IBindingList.
    ReadOnly Property AllowEdit() As Boolean Implements IBindingList.AllowEdit
        Get
            Return True
        End Get
    End Property

    ReadOnly Property AllowNew() As Boolean Implements IBindingList.AllowNew
        Get
            Return True
        End Get
    End Property

    ReadOnly Property AllowRemove() As Boolean Implements IBindingList.AllowRemove
        Get
            Return True
        End Get
    End Property

    ReadOnly Property SupportsChangeNotification() As Boolean Implements IBindingList.SupportsChangeNotification
        Get
            Return True
        End Get
    End Property

    ReadOnly Property SupportsSearching() As Boolean Implements IBindingList.SupportsSearching
        Get
            Return False
        End Get
    End Property

    ReadOnly Property SupportsSorting() As Boolean Implements IBindingList.SupportsSorting
        Get
            Return False
        End Get
    End Property

    ' Events.
    Public Event ListChanged As ListChangedEventHandler Implements IBindingList.ListChanged

    ' Methods.
    Function AddNew() As Object Implements IBindingList.AddNew
        RaiseEvent MyTrace("+CList:AddNew")
        Dim c As New Customer(Me)
        List.Add(c)
        RaiseEvent MyTrace("-CList:AddNew")
        Return c
    End Function

    ' Unsupported properties.
    ReadOnly Property IsSorted() As Boolean Implements IBindingList.IsSorted
        Get
            Throw New NotSupportedException()
        End Get
    End Property

    ReadOnly Property SortDirection() As ListSortDirection Implements IBindingList.SortDirection
        Get
            Throw New NotSupportedException()
        End Get
    End Property

    ReadOnly Property SortProperty() As PropertyDescriptor Implements IBindingList.SortProperty
        Get
            Throw New NotSupportedException()
        End Get
    End Property

    ' Unsupported Methods.
    Sub AddIndex(ByVal prop As PropertyDescriptor) Implements IBindingList.AddIndex
        Throw New NotSupportedException()
    End Sub

    Sub ApplySort(ByVal prop As PropertyDescriptor, ByVal direction As ListSortDirection) Implements IBindingList.ApplySort
        Throw New NotSupportedException()
    End Sub

    Function Find(ByVal prop As PropertyDescriptor, ByVal key As Object) As Integer Implements IBindingList.Find
        Throw New NotSupportedException()
    End Function

    Sub RemoveIndex(ByVal prop As PropertyDescriptor) Implements IBindingList.RemoveIndex
        Throw New NotSupportedException()
    End Sub

    Sub RemoveSort() Implements IBindingList.RemoveSort
        Throw New NotSupportedException()
    End Sub

    Friend Sub MyTrace1(ByVal Mess As String)
        RaiseEvent MyTrace(Mess)
    End Sub

End Class
'------------------------------------------------------------------------------------------------
Avatar of Corey Scheich
Corey Scheich
Flag of United States of America image

instead of using CollectionBase use

Inherits BindingList(Of Customer)

It requires allot less code and already implements everything needed for binding
I modified your code and tested it works well.

' ------------------------------------------------------------------------------------------------
Imports System.ComponentModel           ' Needed for using <Bindable(True)>

Public Class frmCustomers





    Dim Customers As New CustomersList

    Private Sub frmCustomers_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        MyTrace("+frmCust:LoadCustomers")
        Try

            AddHandler Customers.MyTrace, AddressOf MyTrace
            Dim l As IList = CType(Customers, IList)
            l.Add(ReadCustomer(1))
            l.Add(ReadCustomer(2))
            l.Add(ReadCustomer(3))
            l.Add(ReadCustomer(4))
            Me.grdCustomers.DataSource = Customers
            Me.grdCustomers.Refresh()
            MyTrace("-frmCust:LoadCustomers")
        Catch ex As Exception
            MsgBox("Error in '" & Mid(ex.StackTrace, InStrRev(ex.StackTrace, "\") + 1) & "' - " & ex.Message, MsgBoxStyle.Exclamation)
        End Try
    End Sub

    Private Function ReadCustomer(ByVal n As Int16) As Customer
        MyTrace("+CList:ReadCustomer")
        Dim cust As New Customer(Customers)
        cust.FirstName = "First" & n
        cust.LastName = "Last" & n
        MyTrace("-CList:ReadCustomer`")
        Return cust
    End Function

    Private Sub MyTrace(ByVal Mess As String)
        Static iLevel As Int16
        If Mid(Mess, 1, 1) = "+" Then
            Debug.Print(Space(iLevel * 4) & Replace(Mess, "+", "--->", 1, 1))
            iLevel += 1
        ElseIf Mid(Mess, 1, 1) = "-" Then
            iLevel -= 1
            Debug.Print(Space(iLevel * 4) & Replace(Mess, "-", "<---", 1, 1))
        Else
            Debug.Print(Space(iLevel * 4) & Replace(Mess, "=", "    ", 1, 1))
        End If
    End Sub

    Private Sub btnAddRow_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAddRow.Click
        Me.MyTrace("+frm:btnAddNewCustomer_Click")
        Dim cust As New Customer(Me.Customers)
        cust.FirstName = "First1"
        cust.LastName = "Last1"
        Me.Customers.Add(cust)
        MyTrace("-frm:btnAddNewCustomer_Click")
    End Sub

    Private Sub btnDeleteRow_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnDeleteRow.Click
        Me.MyTrace("+frm:btnDeleteRow_Click")
        Me.Customers.RemoveAt(Me.grdCustomers.CurrentRow.Index)
        Me.grdCustomers.Rows.RemoveAt(Me.grdCustomers.CurrentRow.Index)
        MyTrace("-frm:btnDeleteRow_Click")
    End Sub

End Class



Public Class Customer
    Implements IEditableObject
    Public Event TraceMe(ByVal Mess As String)

    Structure CustomerData
        Friend firstName As String
        Friend lastName As String
    End Structure

    Public parent As CustomersList
    Private custData As CustomerData
    Private backupData As CustomerData
    Private inTxn As Boolean = False

    ' Implements IEditableObject
    Sub BeginEdit() Implements IEditableObject.BeginEdit
        _MyParent.MyTrace1("+Cust:BeginEdit")
        If Not inTxn Then
            Me.backupData = custData
            inTxn = True
        End If
        _MyParent.MyTrace1("-Cust:BeginEdit")
    End Sub

    Sub CancelEdit() Implements IEditableObject.CancelEdit
        _MyParent.MyTrace1("+CancelEdit")
        If inTxn Then
            Me.custData = backupData
            inTxn = False
        End If
        _MyParent.MyTrace1("-CancelEdit")
    End Sub

    Sub EndEdit() Implements IEditableObject.EndEdit
        _MyParent.MyTrace1("+EndEdit")
        If inTxn Then
            backupData = New CustomerData()
            inTxn = False
        End If
        _MyParent.MyTrace1("-EndEdit")
    End Sub

    Private _MyParent As CustomersList
    Public Sub New(ByVal objMyParent As CustomersList)
        _MyParent = objMyParent
        _MyParent.MyTrace1("+Cust:New")
        Me.custData = New CustomerData()
        Me.custData.firstName = ""
        Me.custData.lastName = ""
        _MyParent.MyTrace1("-Cust:New")
    End Sub

    Public Property FirstName() As String
        Get
            _MyParent.MyTrace1("=Cust:FirstName<--" & Me.custData.firstName)
            Return Me.custData.firstName
        End Get
        Set(ByVal Value As String)
            _MyParent.MyTrace1("=Cust:FirstName-->" & Value)
            Me.custData.firstName = Value
            Me.OnCustomerChanged()
        End Set
    End Property

    Public Property LastName() As String
        Get
            _MyParent.MyTrace1("=Cust:LastName<--" & Me.custData.lastName)
            Return Me.custData.lastName
        End Get
        Set(ByVal Value As String)
            _MyParent.MyTrace1("=Cust:LastName-->" & Value)
            Me.custData.lastName = Value
            Me.OnCustomerChanged()
        End Set
    End Property

    Friend Property Parents() As CustomersList
        Get
            _MyParent.MyTrace1("=Cust:Parents")
            Return parent
        End Get
        Set(ByVal Value As CustomersList)
            _MyParent.MyTrace1("=Cust:Parents")
            parent = Value
        End Set
    End Property

    Private Sub OnCustomerChanged()
        If Not inTxn And Not (parent Is Nothing) Then
            parent.CustomerChanged(Me)
        End If
    End Sub

    Public Overrides Function ToString() As String
        Dim sb As New IO.StringWriter()
        sb.Write(Me.FirstName)
        sb.Write(" ")
        sb.Write(Me.LastName)
        Return sb.ToString()
    End Function

End Class



Public Class CustomersList
    Inherits BindingList(Of Customer)
    '    Implements INotifyPropertyChanged


    Public Event MyTrace(ByVal Mess As String)

    '    Private resetEvent As New ListChangedEventArgs(ListChangedType.Reset, -1)
    '    Private onListChanged1 As ListChangedEventHandler

    '    Default Public Property Item(ByVal index As Integer) As Customer
    '        Get
    '            RaiseEvent MyTrace("=CList:Item<--")
    '            Return CType(List(index), Customer)
    '        End Get
    '        Set(ByVal Value As Customer)
    '            RaiseEvent MyTrace("=CList:Item-->")
    '            List(index) = Value
    '        End Set
    '    End Property

    '    Public Function Add(ByVal value As Customer) As Integer
    '        RaiseEvent MyTrace("=CList:Add")
    '        Return MyBase.List.Add(value)
    '    End Function

    '    Public Sub Remove(ByVal value As Customer)
    '        RaiseEvent MyTrace("+>CList:Remove")
    '        List.Remove(value)
    '        RaiseEvent MyTrace("-CList:Remove")
    '    End Sub

    '    Protected Overridable Sub OnListChanged(ByVal ev As ListChangedEventArgs)
    '        RaiseEvent MyTrace("+CList:OnListChanged")
    '        If Not (onListChanged1 Is Nothing) Then
    '            onListChanged1(Me, ev)
    '        End If
    '        RaiseEvent MyTrace("-CList:OnListChanged")
    '    End Sub

    '    Protected Overrides Sub OnClear()
    '        RaiseEvent MyTrace("+CList:OnClear")
    '        Dim c As Customer
    '        For Each c In List
    '            c.parent = Nothing
    '        Next c
    '        RaiseEvent MyTrace("-CList:OnClear")
    '    End Sub

    '    Protected Overrides Sub OnClearComplete()
    '        RaiseEvent MyTrace("+CList:OnClearComplete")
    '        OnListChanged(resetEvent)
    '        RaiseEvent MyTrace("-CList:OnClearComplete")
    '    End Sub

    '    Protected Overrides Sub OnInsertComplete(ByVal index As Integer, ByVal value As Object)
    '        RaiseEvent MyTrace("+CList:OnInsertComplete")
    '        Dim c As Customer = CType(value, Customer)
    '        c.parent = Me
    '        OnListChanged(New ListChangedEventArgs(ListChangedType.ItemAdded, index))
    '        RaiseEvent MyTrace("-CList:OnInsertComplete")
    '    End Sub

    '    Protected Overrides Sub OnRemoveComplete(ByVal index As Integer, ByVal value As Object)
    '        RaiseEvent MyTrace("+CList:OnRemoveComplete")
    '        Dim c As Customer = CType(value, Customer)
    '        c.parent = Me
    '        OnListChanged(New ListChangedEventArgs(ListChangedType.ItemDeleted, index))
    '        RaiseEvent MyTrace("-CList:OnRemoveComplete")
    '    End Sub

    '    Protected Overrides Sub OnSetComplete(ByVal index As Integer, ByVal oldValue As Object, ByVal newValue As Object)
    '        RaiseEvent MyTrace("+CList:OnSetComplete")
    '        If oldValue <> newValue Then
    '            Dim oldcust As Customer = CType(oldValue, Customer)
    '            Dim newcust As Customer = CType(newValue, Customer)
    '            oldcust.parent = Nothing
    '            newcust.parent = Me
    '            OnListChanged(New ListChangedEventArgs(ListChangedType.ItemAdded, index))
    '        End If
    '        RaiseEvent MyTrace("-CList:OnSetComplete")
    '    End Sub

    Friend Sub CustomerChanged(ByVal cust As Customer)
        RaiseEvent MyTrace("+CList:CustomerChanged")
        Dim index As Integer = Me.IndexOf(cust)
        OnListChanged(New ListChangedEventArgs(ListChangedType.ItemChanged, index))
        RaiseEvent MyTrace("-CList:CustomerChanged")
    End Sub

    '    ' Implements IBindingList.
    '    ReadOnly Property AllowEdit() As Boolean Implements IBindingList.AllowEdit
    '        Get
    '            Return True
    '        End Get
    '    End Property

    '    ReadOnly Property AllowNew() As Boolean Implements IBindingList.AllowNew
    '        Get
    '            Return True
    '        End Get
    '    End Property

    '    ReadOnly Property AllowRemove() As Boolean Implements IBindingList.AllowRemove
    '        Get
    '            Return True
    '        End Get
    '    End Property

    '    ReadOnly Property SupportsChangeNotification() As Boolean Implements IBindingList.SupportsChangeNotification
    '        Get
    '            Return True
    '        End Get
    '    End Property

    '    ReadOnly Property SupportsSearching() As Boolean Implements IBindingList.SupportsSearching
    '        Get
    '            Return False
    '        End Get
    '    End Property

    '    ReadOnly Property SupportsSorting() As Boolean Implements IBindingList.SupportsSorting
    '        Get
    '            Return False
    '        End Get
    '    End Property

    '    ' Events.
    '    Public Event ListChanged As ListChangedEventHandler Implements IBindingList.ListChanged

    '    ' Methods.
    '    Function AddNew() As Object Implements IBindingList.AddNew
    '        RaiseEvent MyTrace("+CList:AddNew")
    '        Dim c As New Customer(Me)
    '        List.Add(c)
    '        RaiseEvent MyTrace("-CList:AddNew")
    '        Return c
    '    End Function

    '    ' Unsupported properties.
    '    ReadOnly Property IsSorted() As Boolean Implements IBindingList.IsSorted
    '        Get
    '            Throw New NotSupportedException()
    '        End Get
    '    End Property

    '    ReadOnly Property SortDirection() As ListSortDirection Implements IBindingList.SortDirection
    '        Get
    '            Throw New NotSupportedException()
    '        End Get
    '    End Property

    '    ReadOnly Property SortProperty() As PropertyDescriptor Implements IBindingList.SortProperty
    '        Get
    '            Throw New NotSupportedException()
    '        End Get
    '    End Property

    '    ' Unsupported Methods.
    '    Sub AddIndex(ByVal prop As PropertyDescriptor) Implements IBindingList.AddIndex
    '        Throw New NotSupportedException()
    '    End Sub

    '    Sub ApplySort(ByVal prop As PropertyDescriptor, ByVal direction As ListSortDirection) Implements IBindingList.ApplySort
    '        Throw New NotSupportedException()
    '    End Sub

    '    Function Find(ByVal prop As PropertyDescriptor, ByVal key As Object) As Integer Implements IBindingList.Find
    '        Throw New NotSupportedException()
    '    End Function

    '    Sub RemoveIndex(ByVal prop As PropertyDescriptor) Implements IBindingList.RemoveIndex
    '        Throw New NotSupportedException()
    '    End Sub

    '    Sub RemoveSort() Implements IBindingList.RemoveSort
    '        Throw New NotSupportedException()
    '    End Sub

    Friend Sub MyTrace1(ByVal Mess As String)
        RaiseEvent MyTrace(Mess)
    End Sub

    '    Public Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
End Class
Avatar of gem56
gem56

ASKER

Hi Corey2,
Thanks a lot, that's exactly what I need. Seeing that you know your stuff ;-) maybe you can help me with a few additional questions.

1) If I programmatically change the underlying data it doesn't get reflected in DataGridView unles I execute 'grdCustomers.UpdateCellValue'. It's no big deal but I was just wondering if that is just the way it is or can that be automated?
2) I can now insert rows programmatically to the collection but not directly into DataGridView. I don't need to do that now but, for future reference, is that just the way it is?
3) What' the easies way of detecting change in Cell contents? I was going to use 'IEditableObject.EndEdit' but is there a better way?

Cheers,
     Michael
1) Modify your
Public Class Customer
          Implements INotifyPropertyChanged

'then you must raise the event through the set method of the property
'this will notify the list that a change has been made to one of the items

    Public Property FirstName() As String
        Get
            _MyParent.MyTrace1("=Cust:FirstName<--" & Me.custData.firstName)
            Return Me.custData.firstName
        End Get
        Set(ByVal Value As String)
            _MyParent.MyTrace1("=Cust:FirstName-->" & Value)
            Me.custData.firstName = Value
            Me.OnCustomerChanged()
'the following 2 lines need to be added to every property to raise the event
'no edits need to be made to either line they will send the appropriate data no matter what
            Dim PropName As String = System.Reflection.MethodBase.GetCurrentMethod.Name
            RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs(PropName.Remove(0, 4)))
        End Set
    End Property

2) You cannot add items because there is not Sub New for the Customer Class that doesn't require a parameter

3)     Private Sub grdCustomers_CellEndEdit(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles grdCustomers.CellEndEdit

    End Sub
Avatar of gem56

ASKER

Once again, you were spot on so thanks a lot.

Just one final clarification. For point 2) you said that I'm unable to (programmatically) insert rows to DataGridView because my Customer Class doesn't have Sub New. I created an empty Sub New (not sure whether it needs anything though) and I'm getting the same response "Rows cannot be programmatically added to the dataGridView's rows collection when the control data-bound".

Maybe I've misunderstood you or should the Sub New have something in it?

I'm still interested on this point because if that was possible than (for easier maintenance) I could off load some functionality into the DataGridView rather than have it in my other class.

Cheers,
     Michael
You currently have the following code in the customer class
 
   Private _MyParent As CustomersList
    Public Sub New(ByVal objMyParent As CustomersList)
        _MyParent = objMyParent
        _MyParent.MyTrace1("+Cust:New")
        Me.custData = New CustomerData()
        Me.custData.firstName = ""
        Me.custData.lastName = ""
        _MyParent.MyTrace1("-Cust:New")
    End Sub

'add this code
Public Sub New() 'donot add any params
'add any code you need here
end sub

That is all I did to get the Datagrid to work with the example I posted above.
ASKER CERTIFIED SOLUTION
Avatar of Corey Scheich
Corey Scheich
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of gem56

ASKER

Hi Corey2,
On my end everything else works except for the insertion of a row into DGV (using code) however as you've answered the initial question (plus some) I've decided to close this question and open another "https://www.experts-exchange.com/questions/22741618/Problem-implementing-data-binding-with-DataGridView.html", and linked it to this question.
If you don't mind I'd appreciate you commnting on the new question, as you know exactly what's qoing on and have been most helpful.

Thanks a lot,
     Michael