elroyskimms
Member
- Joined
- Jul 10, 2015
- Messages
- 19
- Programming Experience
- 10+
I have a CheckedListBox with Items in it. If I iterate through the Items collection with a For Each loop and check if the SelectedItems collection contains the current Item, the For Each loop breaks on Next, acting as if I modified the collection. But I didn't modify the collection at all. I've seen this happen in multi-threaded applications where one thread is looping and another thread is editing, and I understand why it fails. But in this case, I have no other threads running at all. I have a simple WinForm app you can paste into a project. I am walking through the Items collection and checking against the SelectedItems collection. I know I can change For Each to For I as integer.... etc and iterate using the Index values without a problem. But I want to understand WHY this happens in a single-thread environment. Am I modifying the collection somewhere and not realizing it?
-E
List that this enumerator is bound to has been modified. An enumerator can only be used if the list does not change.
at System.Windows.Forms.ListBox.ItemArray.EntryEnumerator.System.Collections.IEnumerator.MoveNext()
-E
VB.NET:
Public Class Form1
Public Property clbBroken As New CheckedListBox With {.Width = 300, .Height = 300, .CheckOnClick = True}
Public Property txtResults As New TextBox With {.Multiline = True, .Width = 300, .Height = 300}
Public Property btnDoStuff As New Button With {.Text = "Do It", .Width = 150}
Public Property MyPanel As New FlowLayoutPanel With {.Width = 615, .Height = 395, .FlowDirection = FlowDirection.LeftToRight}
Private Sub Form1_Shown(sender As Object, e As EventArgs) Handles Me.Shown
Me.Width = 650
Me.Height = 400
Me.Controls.Add(MyPanel)
MyPanel.Controls.Add(clbBroken)
MyPanel.Controls.Add(txtResults)
AddHandler btnDoStuff.Click, AddressOf btnDoStuff_Click
MyPanel.Controls.Add(btnDoStuff)
For i As Integer = 1 To 5
'Load the CheckedListBox
clbBroken.Items.Add(New SimpleClass)
Next
End Sub
Private Sub btnDoStuff_Click(sender As Object, e As EventArgs)
Try
For Each MySimpleClass As SimpleClass In clbBroken.Items
If clbBroken.SelectedItems.Contains(MySimpleClass) Then
txtResults.Text &= MySimpleClass.ToString & vbCrLf
End If
'This will throw an exception even though nothing is actually changing the List. We're just looking inside the SelectedItems collection.
Next
Catch Er As Exception
txtResults.Text &= "EXCEPTION" & vbCrLf & Er.Message & vbCrLf & Er.StackTrace & vbCrLf
End Try
End Sub
End Class
Public Class SimpleClass
Public Property ID As Guid = Guid.NewGuid
Public Overrides Function ToString() As String
Return ID.ToString
End Function
End Class
List that this enumerator is bound to has been modified. An enumerator can only be used if the list does not change.
at System.Windows.Forms.ListBox.ItemArray.EntryEnumerator.System.Collections.IEnumerator.MoveNext()