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