I am attempting to bind some datagridviews to my collections of obects. The collection inherits from CollectionBase and implements IBindingList. The problem it's giving me is whenever I start deleting stuff I start getting these annoying IndexOutOfRange exceptions within the data error event.

The following exception occurred in the DataGridView:

System.IndexOutOfRangeException: Index 6 does not have a value.
at System.Windows.Forms.CurrencyManager.get_Item(Int32 index)
at System.Windows.Forms.DataGridView.DataGridViewDataConnection.GetErrors

This is my base collection class. Thanks to anyone who helps.

Code Snippet

Imports System.Collections
Imports System.ComponentModel
Imports System.Xml.Serialization
Imports System.io
Imports System.Windows.Forms

Public Class CountEventArgs
Inherits EventArgs
'purpose: common count change for articles and collections


Public Enum ChangeTypes
[Increased]
[Decreased]
[Cleared]
End Enum

Private _ChangeType As ChangeTypes
Private _Item As Object = Nothing

Public Property ChangeType() As ChangeTypes
Get
Return _ChangeType
End Get
Set(ByVal value As ChangeTypes)
_ChangeType = value
End Set
End Property

Public Property Item() As Object
Get
Return _Item
End Get
Set(ByVal value As Object)
_Item = value
End Set
End Property

Public Sub New(ByVal changetype As ChangeTypes, ByVal item As Object)
MyBase.New()
_ChangeType = changetype
_Item = item
End Sub
Public Sub New(ByVal changeType As ChangeTypes)
Me.New(changeType, Nothing)
End Sub

End Class


Public MustInherit Class KeyedCollectionBase
Inherits CollectionBase
Implements IBindingList
Implements IXmlSerializable

Protected keys As New SortedList()
Protected keymember As String
Private boundgrid As DataGridView
#Region "Inerited and passed around"


Public Event CountChange(ByVal sender As Object, ByVal e As CountEventArgs)

Protected Function Add(ByVal Items As KeyedCollectionBase) As Integer()
Dim al As New ArrayList()
Dim itm As Object
For Each itm In Items
Dim key As Object = itm.GetType.GetProperty(keymember).GetValue(itm, Nothing)
keys.Add(key, MyBase.List.Add(itm))
al.Add(keys(key))
Next
Return al.ToArray(GetType(Integer))
End Function

Protected Function Add(ByVal Items() As Object) As Integer()
Dim al As New ArrayList()
Dim itm As Object
For Each itm In Items
Dim key As Object = itm.GetType.GetProperty(keymember).GetValue(itm, Nothing)
keys.Add(key, MyBase.List(itm))
al.Add(keys(key))
Next
Return al.ToArray(GetType(Integer))
End Function

Protected Function Add(ByVal item As Object) As Integer
'keymember = "CommissionPercent"
Dim i As Integer = -1
Try

Dim key As Object = item.GetType.GetProperty(keymember).GetValue(item, Nothing)
i = MyBase.List.Add(item)
keys.Add(key, i)
Return keys(key)

Catch ex As Exception
MyBase.RemoveAt(i)
Debug.WriteLine(ex.ToString())
Return -1
End Try
End Function

Protected Function add(ByVal item As Object, ByVal key As Object) As Integer
Dim i As Integer = -1
i = MyBase.List.Add(item)
Try
keys.Add(key, i)
Catch ex As Exception
MyBase.RemoveAt(i)
Debug.WriteLine(ex.ToString())
End Try

Return keys(key)
End Function

Default Protected ReadOnly Property Item(ByVal key As String) As Object
Get
Return MyBase.List.Item(keys(key))
End Get
End Property

Default Protected ReadOnly Property Item(ByVal index As Integer) As Object
Get
Return MyBase.List.Item(index)
End Get
End Property

Protected Sub Remove(ByVal Item As Object)
Dim Index As Integer = keys.IndexOfValue(Me.IndexOf(Me.keyof(Item)))
keys.RemoveAt(Index)
MyBase.List.Remove(Item)
DecreaseIndexes(Index)
End Sub

Public Shadows Sub RemoveAt(ByVal key As Object)
Dim Index As Integer = keys(key)
keys.Remove(key)
MyBase.List.RemoveAt(Index)
DecreaseIndexes(Index)
End Sub

Public Shadows Sub RemoveAt(ByVal index As Integer)
keys.RemoveAt(keys.IndexOfValue(index))
MyBase.List.RemoveAt(index)
DecreaseIndexes(index)
End Sub

Public Function IndexOf(ByVal key As Object) As Integer
Return MyBase.List.IndexOf(MyBase.List.Item(keys(key)))
End Function

Public Function IndexOf(ByVal Item As Integer) As Integer
MyBase.List.IndexOf(Item)
End Function

Public Function KeyOf(ByVal Item As Object) As Object
Return keys.GetKeyList.Item(keys.IndexOfValue(MyBase.List.IndexOf(Item)))
End Function

Protected Sub Insert(ByVal Index As Integer, ByVal Item As Object)
Dim key As Object = Item.GetType.GetProperty(keymember).GetValue(Item, Nothing)
IncreaseIndexes(Index)
keys.Add(key, Index)
MyBase.List.Insert(Index, Item)
End Sub

Protected Sub Insert(ByVal Index As Integer, ByVal Item As Object, ByVal Key As Object)
IncreaseIndexes(Index)
keys.Add(Key, Index)
MyBase.List.Insert(Index, Item)
End Sub

Protected Function Contains(ByVal Item As Object) As Boolean
Return MyBase.List.Contains(Item)
End Function

Public Sub New(ByVal KeyMember As String)
MyBase.New()

Me.keymember = KeyMember
End Sub

Protected Overrides Sub OnClearComplete()
MyBase.OnClearComplete()
If Not boundgrid Is Nothing Then RefreshGrid()

RaiseEvent CountChange(Me, New CountEventArgs(CountEventArgs.ChangeTypes.Cleared))
End Sub

Protected Overrides Sub OnInsertComplete(ByVal index As Integer, ByVal value As Object)
MyBase.OnInsertComplete(index, value)

If Not boundgrid Is Nothing Then RefreshGrid()

RaiseEvent CountChange(Me, New CountEventArgs(CountEventArgs.ChangeTypes.Increased, value))
End Sub

Protected Overrides Sub OnRemoveComplete(ByVal index As Integer, ByVal value As Object)
MyBase.OnRemoveComplete(index, value)

If Not boundgrid Is Nothing Then RefreshGrid()

RaiseEvent CountChange(Me, New CountEventArgs(CountEventArgs.ChangeTypes.Decreased, value))
End Sub


Protected Overrides Sub OnSetComplete(ByVal index As Integer, ByVal oldValue As Object, ByVal newValue As Object)
MyBase.OnSetComplete(index, oldValue, newValue)
If Not boundgrid Is Nothing Then RefreshGrid()
End Sub

Public Sub CopyTo(ByVal array As System.Array, ByVal index As Integer)
MyBase.InnerList.CopyTo(array, index)
End Sub

Public Sub NoundDataGrid(ByVal dg As DataGridView)
boundgrid = dg
End Sub

Private Sub IncreaseIndexes(ByVal start As Integer)
Dim values As IList = keys.GetValueList()
Dim cnt As Integer
Dim cntMax As Integer = values.Count - 1
For cnt = cntMax To 0 Step -1
If values(cnt) >= start Then
keys.SetByIndex(keys.IndexOfValue(values(cnt)), values(cnt + 1))
End If

Next
End Sub

Private Sub DecreaseIndexes(ByVal start As Integer)
Dim values As IList = keys.GetValueList()
Dim cnt As Integer
Dim cntMax As Integer = values.Count - 1
For cnt = cntMax To 0 Step -1
If values(cnt) >= start Then
keys.SetByIndex(keys.IndexOfValue(values(cnt)), values(cnt) - 1)

End If
Next
End Sub

Private Sub RefreshGrid()
'boundgrid.Refresh()
Try
boundgrid.CancelEdit()
boundgrid.DataBindings.Clear()
boundgrid.DataSource = Nothing
boundgrid.DataSource = Me
Catch ex As Exception
Debug.WriteLine(ex.ToString())
End Try
End Sub

#End Region



#Region "IBindingList"

Public Sub AddIndex(ByVal [property] As System.ComponentModel.PropertyDescriptor) Implements System.ComponentModel.IBindingList.AddIndex

End Sub

Public MustOverride Function AddNew() As Object Implements System.ComponentModel.IBindingList.AddNew



Public ReadOnly Property AllowEdit() As Boolean Implements System.ComponentModel.IBindingList.AllowEdit
Get
Return True
End Get
End Property

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

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

Public Sub ApplySort(ByVal [property] As System.ComponentModel.PropertyDescriptor, ByVal direction As System.ComponentModel.ListSortDirection) Implements System.ComponentModel.IBindingList.ApplySort

End Sub

Public Function Find(ByVal [property] As System.ComponentModel.PropertyDescriptor, ByVal key As Object) As Integer Implements System.ComponentModel.IBindingList.Find
Return Nothing
End Function

Public ReadOnly Property IsSorted() As Boolean Implements System.ComponentModel.IBindingList.IsSorted
Get
Return True
End Get
End Property

Public Event ListChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ListChangedEventArgs) Implements System.ComponentModel.IBindingList.ListChanged

Public Sub RemoveIndex(ByVal [property] As System.ComponentModel.PropertyDescriptor) Implements System.ComponentModel.IBindingList.RemoveIndex

End Sub

Public Sub RemoveSort() Implements System.ComponentModel.IBindingList.RemoveSort

End Sub

Public ReadOnly Property SortDirection() As System.ComponentModel.ListSortDirection Implements System.ComponentModel.IBindingList.SortDirection
Get
Return ListSortDirection.Ascending
End Get
End Property

Public ReadOnly Property SortProperty() As System.ComponentModel.PropertyDescriptor Implements System.ComponentModel.IBindingList.SortProperty
Get
Return Nothing
End Get
End Property

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

Public ReadOnly Property SupportsSearching() As Boolean Implements System.ComponentModel.IBindingList.SupportsSearching
Get
Return True
End Get
End Property

Public ReadOnly Property SupportsSorting() As Boolean Implements System.ComponentModel.IBindingList.SupportsSorting
Get
Return True
End Get
End Property
#End Region
#Region "IXMLSerializable"



Public MustOverride Function GetSchema() As System.Xml.Schema.XmlSchema Implements System.Xml.Serialization.IXmlSerializable.GetSchema



Public MustOverride Sub ReadXml(ByVal reader As System.Xml.XmlReader) Implements System.Xml.Serialization.IXmlSerializable.ReadXml


Public MustOverride Sub WriteXml(ByVal writer As System.Xml.XmlWriter) Implements System.Xml.Serialization.IXmlSerializable.WriteXml


#End Region
End Class


This is the implemented class the is made the data source

Public Class CommissionRates
Inherits KeyedCollectionBase

Public DefaultCommissionRate As Decimal = 0


Public Shadows Function Add(ByVal obj As CommissionRate) As Integer
Return MyBase.Add(obj)
'List.Add(obj)
'Me.Sort()
'Return List.IndexOf(obj)
End Function

Public Shadows Function Add(ByVal Item As CommissionRate, ByVal key As Object) As Integer
Return MyBase.Add(Item, key)
End Function

Default Public Shadows ReadOnly Property Item(ByVal key As String) As CommissionRate
Get
Return MyBase.Item(key)
End Get
End Property

Default Public Shadows ReadOnly Property Item(ByVal Index As Integer) As CommissionRate
Get
Return MyBase.Item(Index)
End Get
End Property



Public Shadows Sub Remove(ByVal obj As CommissionRate)
Try
MyBase.Remove(obj)
'List.Remove(obj)
Catch ex As Exception
Debug.WriteLine(ex.ToString())
End Try
End Sub

Public Shadows Sub Insert(ByVal key As Object, ByVal Item As CommissionRate)
MyBase.Insert(key, Item)
End Sub

Public Shadows Sub Insert(ByVal Index As Integer, ByVal Item As CommissionRate)
MyBase.Insert(Index, Item)
End Sub

Public Shadows Function Contains(ByVal Item As CommissionRate) As Boolean
Return MyBase.Contains(Item)
End Function

Public Sub New(ByVal keymember As String)
MyBase.New(keymember)
End Sub

Public Overrides Function AddNew() As Object
Dim cr As New CommissionRate(0, 0, 0)
Me.Add(cr)
cr.parent = Me
Return cr
End Function

'Public ReadOnly Property Item(ByVal index As Integer) As CommissionRate
' Get
' If Not (index > Count - 1 Or index < 0) Then
' Return CType(List.Item(index), CommissionRate)
' Else
' Return Nothing
' End If
' End Get
'End Property
'Public Sub Remove(ByVal index As Integer)
' If Not (index > Count - 1 Or index < 0) Then
' CType(List.Item(index), CommissionRate).parent = Nothing
' List.RemoveAt(index)
' Me.Sort()
' End If
'End Sub
Public Sub Sort()
If List.Count < 2 Then Exit Sub

Dim i As Integer = 0
Dim j As Integer = (List.Count - 1)
Dim dontSort As Boolean = False
Do Until dontSort
dontSort = True




For i = 1 To j
Dim temp As CommissionRate
temp = CType(List.Item(i), CommissionRate)
If CType(List.Item(0), CommissionRate).CompareTo(temp) > 0 Then
dontSort = False
List.RemoveAt(i)
List.Insert(0, temp)

End If

Next
Loop
OnListChanged(New ListChangedEventArgs(ListChangedType.Reset, 0))

End Sub

Public Function GetCommissionRate(ByVal TotalLoans As Integer, ByVal LifeSales As Integer, ByVal DisabilitySales As Integer) As Decimal
'Me.Sort()
Dim i As IEnumerator = Me.GetEnumerator()

While (i.MoveNext)
Dim temp As CommissionRate
temp = CType(i.Current, CommissionRate)
If temp.MatchRate(TotalLoans, LifeSales, DisabilitySales) Then
Return temp.CommissionPercent
End If

End While
Return DefaultCommissionRate
End Function


Public Overrides Function GetSchema() As System.Xml.Schema.XmlSchema
Return Nothing
End Function

Public Overrides Sub ReadXml(ByVal reader As System.Xml.XmlReader)
Dim xread As XmlNodeReader = reader
If (xread.Name = "COMMISSIONRATES" And Not xread.IsEmptyElement) Then
Do
xread.Read()
If xread.Name = "COMMISSIONRATE" Then
Dim cr As New CommissionRate()
cr.ReadXml(xread)
Me.Add(cr)
End If

Loop Until xread.EOF Or xread.Name = "COMMISSIONRATES" Or xread.Name = "PRODUCT" Or xread.Name = "COMPANY" Or xread.Name = "COMPANIES"
End If
End Sub

Public Overrides Sub WriteXml(ByVal writer As System.Xml.XmlWriter)
Dim itr As IEnumerator = Me.GetEnumerator()
While (itr.MoveNext())
Dim tempCR As CommissionRate = CType(itr.Current, CommissionRate)
tempCR.WriteXml(writer)
End While

End Sub





Public Shadows Sub ApplySort(ByVal [property] As System.ComponentModel.PropertyDescriptor, ByVal direction As System.ComponentModel.ListSortDirection)
'Me.Sort()
End Sub




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

Protected Overridable Sub OnListChanged(ByVal ev As ListChangedEventArgs)
If (onListChanged1 IsNot Nothing) Then
onListChanged1(Me, ev)
End If
End Sub




Protected Overrides Sub OnClear()

Dim cr As CommissionRate
For Each cr In List
cr.parent = Nothing
Next
MyBase.Clear()
End Sub

Protected Overrides Sub OnClearComplete()
MyBase.OnClearComplete()
OnListChanged(resetEvent)
End Sub

Protected Overrides Sub OnInsertComplete(ByVal index As Integer, ByVal value As Object)
MyBase.OnInsertComplete(index, value)
Dim cr As CommissionRate = CType(value, CommissionRate)
cr.parent = Me
'OnListChanged(New ListChangedEventArgs(ListChangedType.ItemAdded, index))
End Sub

Protected Overrides Sub OnRemoveComplete(ByVal index As Integer, ByVal value As Object)
MyBase.OnRemoveComplete(index, value)
Dim cr As CommissionRate = CType(value, CommissionRate)
cr.parent = Nothing
'OnListChanged(New ListChangedEventArgs(ListChangedType.ItemDeleted, index))

End Sub

Protected Overrides Sub OnSetComplete(ByVal index As Integer, ByVal oldValue As Object, ByVal newValue As Object)
MyBase.OnSetComplete(index, oldValue, newValue)
If oldValue <> newValue Then
Dim oldCR As CommissionRate = CType(oldValue, CommissionRate)
Dim newCR As CommissionRate = CType(newValue, CommissionRate)

oldCR.parent = Nothing
newCR.parent = Me

'OnListChanged(New ListChangedEventArgs(ListChangedType.ItemAdded, index))

End If
End Sub

Friend Sub CommissionRateChanged(ByVal commRate As CommissionRate)
Dim index As Integer = List.IndexOf(commRate)
OnListChanged(New ListChangedEventArgs(ListChangedType.ItemChanged, index))
End Sub

Public Shadows Event ListChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ListChangedEventArgs)
End Class