简体   繁体   中英

Visual Basic Form doesn't dispose all items when asked to

hope someone can help..

I'm writing a little Windows application with VB.NET forms,

I've created a subroutine which disposes all the items on the form when it is called:

Sub disposer() 'disposes of all the items in the form

        For Each i In Me.Controls

            i.dispose

        Next

End Sub

The above, if I'm correct should dispose of everything in the form, however, it appears to only get rid of some items on the form, for example, only half the textboxes, for example.

What happens: you're iterating over the collection of Controls of a Form (or another class that inherits Control ).

Each time you call Dispose() on one of its members, you actively remove it from the collection, so you're modifying the collection you're iterating over.

When you dispose of the first Control, this is removed from the collection and the next Control in the list takes its place .
Your loop calls Enumerator.MoveNext() , so when you call Dispose() again, you're disposing of the element at index 1, which was previously the element at index 2.
The element which was at index 1, now at index 0, is skipped.
This process goes on, the result is that you're disposing of half of the Controls in the collection.

You can test it with:

For Each ctrl As Control In Me.Controls
    ctrl.Dispose()
    Console.WriteLine(Me.Controls.Count)
Next

You'll see that the final count is half the measure of the initial count: half of the Controls are still very much alive.

You can use a backwards For loop (from [Collection].Count - 1 to 0 ), starting from the top of the collection.
In this case, when you dispose of a Control, the Collection is resized from the top so Enumerator.MovePrevious() won't skip any element in the collection.

For i As Integer = Me.Controls.Count - 1 To 0 Step -1
    Me.Controls(i).Dispose()
Next

You can also use a forward loop and dispose at Index 0. When the element at Index 0 is disposed of, the next in line will take its place at that index, so again you won't skip any. The elements in the collection are constantly moved towards the bottom in this case, though, so it's quite a slower process.
If the collection has a small amount of items, you won't notice, but keep it in mind.

For i As Integer = 0 To Me.Controls.Count - 1
    Me.Controls(0).Dispose()
Next

You can also filter the collection of Controls, to only consider a specific Type.
For example, to dispose of all TextBox Controls child of the Form (or any other class derived from Control):

Dim textBoxes = Me.Controls.OfType(Of TextBox).ToList()
For i As Integer = textBoxes.Count - 1 To 0 Step -1
    textBoxes(i).Dispose()
Next

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM