Discussion:
Zombie Controls
(too old to reply)
Patrick A
2009-12-31 22:49:13 UTC
Permalink
Can anyone help me understand why neither of the following code snips
won't clear all of the Buttons on my form?

'A: Specify Buttons
For Each ctl As Control In Me.Controls
If TypeOf ctl Is Button Then
Me.Controls.Remove(ctl)
End If
Next

'B: Specify Not Menu Strip
For Each ctl As Control In Me.Controls
If Not TypeOf ctl Is MenuStrip Then
Me.Controls.Remove(ctl)
End If
Next
Random
2009-12-31 23:44:44 UTC
Permalink
Post by Patrick A
Can anyone help me understand why neither of the following code snips
won't clear all of the Buttons on my form?
Two problems: You're modifying an array as you're iterating over it,
that's not allowed. Also, you're only checking for child controls of
the form itself. Any buttons in a frame or other control container
within the form itself won't be seen by this loop. Something like
this should fix both issues:

Dim toRemove As New Queue(Of Control)
Dim toCheck As New Queue(Of Control)

For Each ctl As Control In Me.Controls
toCheck.Enqueue(ctl)
Next

While toCheck.Count > 0
Dim ctl As Control = toCheck.Dequeue()

For Each other As Control In ctl.Controls
toCheck.Enqueue(other)
Next

If TypeOf ctl Is Button Then
toRemove.Enqueue(ctl)
End If
End While

While toRemove.Count > 0
Dim ctl As Control = toRemove.Dequeue()
ctl.Parent.Controls.Remove(ctl)
End While
Patrick A
2010-01-01 19:59:32 UTC
Permalink
Random,

Thanks very much for the thorough explanation and the code.

I'll have to read up on Enqueue and DeQueue.

If I only want to check for child controls of the form (in this case I
do) would I just comment out these lines?

For Each other As Control In ctl.Controls
toCheck.Enqueue(other)
Next

Nevermind if I'm being too lazy - I can try for myself later - I'm not
in the office.

Thanks again,

Patrick
Post by Patrick A
Can anyone help me understand why neither of the following code snips
won't clear all of the Buttons on my form?
Two problems:  You're modifying an array as you're iterating over it,
that's not allowed.  Also, you're only checking for child controls of
the form itself.  Any buttons in a frame or other control container
within the form itself won't be seen by this loop.  Something like
Dim toRemove As New Queue(Of Control)
Dim toCheck As New Queue(Of Control)
For Each ctl As Control In Me.Controls
    toCheck.Enqueue(ctl)
Next
While toCheck.Count > 0
    Dim ctl As Control = toCheck.Dequeue()
    For Each other As Control In ctl.Controls
        toCheck.Enqueue(other)
    Next
    If TypeOf ctl Is Button Then
        toRemove.Enqueue(ctl)
    End If
End While
While toRemove.Count > 0
    Dim ctl As Control = toRemove.Dequeue()
    ctl.Parent.Controls.Remove(ctl)
End While
Random
2010-01-02 01:47:49 UTC
Permalink
Post by Patrick A
If I only want to check for child controls of the form (in this case I
do) would I just comment out these lines?
That'd work, but you could get rid of the toCheck queue all together:

Dim toRemove As New Queue(Of Control)

For Each ctl As Control In Me.Controls
If TypeOf ctl Is Button Then
toRemove.Enqueue(ctl)
End If
Next

While toRemove.Count > 0
Dim ctl As Control = toRemove.Dequeue()
ctl.Parent.Controls.Remove(ctl)
End While
Mick Doherty
2010-01-02 10:06:24 UTC
Permalink
Just as an option:

You can also loop through the controls in reverse and remove them by index
(ForEach is no good because the iteration count keeps changing as you remove
items, but For is OK).

-- 8< -----------------------------------------------------------

For id As Int32 = Me.Controls.Count - 1 To 0 Step-1
If TypeOf Me.Controls(id) Is Button Then
Me.Controls.RemoveAt(id)
End If
Next

-- 8< -----------------------------------------------------------

Note: You must loop in reverse as, otherwise, each control will re-index
itself as a lower indexed control is removed and you'll end up with an index
out of range exception.
--
Mick Doherty
http://dotnetrix.co.uk/nothing.htm
Post by Patrick A
Random,
Thanks very much for the thorough explanation and the code.
I'll have to read up on Enqueue and DeQueue.
If I only want to check for child controls of the form (in this case I
do) would I just comment out these lines?
For Each other As Control In ctl.Controls
toCheck.Enqueue(other)
Next
Nevermind if I'm being too lazy - I can try for myself later - I'm not
in the office.
Thanks again,
Patrick
Post by Random
Post by Patrick A
Can anyone help me understand why neither of the following code snips
won't clear all of the Buttons on my form?
Two problems: You're modifying an array as you're iterating over it,
that's not allowed. Also, you're only checking for child controls of
the form itself. Any buttons in a frame or other control container
within the form itself won't be seen by this loop. Something like
Dim toRemove As New Queue(Of Control)
Dim toCheck As New Queue(Of Control)
For Each ctl As Control In Me.Controls
toCheck.Enqueue(ctl)
Next
While toCheck.Count > 0
Dim ctl As Control = toCheck.Dequeue()
For Each other As Control In ctl.Controls
toCheck.Enqueue(other)
Next
If TypeOf ctl Is Button Then
toRemove.Enqueue(ctl)
End If
End While
While toRemove.Count > 0
Dim ctl As Control = toRemove.Dequeue()
ctl.Parent.Controls.Remove(ctl)
End While
Jeff Johnson
2010-01-04 14:16:01 UTC
Permalink
Post by Random
Dim toRemove As New Queue(Of Control)
Any particular reason you used a Queue instead of a List?
Random
2010-01-04 16:19:52 UTC
Permalink
Post by Jeff Johnson
Post by Random
Dim toRemove As New Queue(Of Control)
Any particular reason you used a Queue instead of a List?
Nope. Either would work.

Loading...