foreach findet nur die Hälfte der Controls

I

Izzy84

Hallo Forum,

ich werde noch verrückt hier... :(
Ich versuche eigtl nur alle Buttons, Labels und Textboxen auf meiner Form zu entfernen, sobald ein Button gedrückt wird, so das nichts übrig bleibt ausser einer einzigen Picturebox. Ich hab keine Panels o.ä., es liegt alles direkt auf der Form.

C#:
foreach(Control ctrl in this.Controls)
{
     if(ctrl.getType() != typeof(PictureBox))
     {
          this.Controls.Remove(ctrl);
          ctrl.Dispose();
     }
}

Auf diese Weise verschwinden aber lediglich ein paar der Controls, niemals alle.
Wenn ich mir die ControlsCollection von this.Controls anschaue, stehen dort aber alle drinne.
Wieso werden die über die Schleife nicht gefunden und entfernt ?
Ich verstehs leider nicht wirklich...
 
Kann es sein das du den Button entfernst der diese Funktion aufgerufen hat? Möglicherweise laufen Event-Handler nicht mehr wenn du den Sender Disposed
 
Dispose zu verwenden muss nicht zwingend bedeuten das ein Control auch "verschwindet".

Versuchs mal so :
C#:
for (int i = this.Controls.Count-1; i >= 0; i--)
            {
                if (!(this.Controls[i] is PictureBox))
                {
                    this.Controls.RemoveAt(i);
                }
            }
 
@rd4eva: Da steht eh ein remove drinnen.
Trotzdem bringtst du mich auf eine gute Idee. Soweit ich weiß darf man bei Collections durch die man mit foreach durchläuft nicht hinzufügen oder entfernen. Also ev. mal die Version mit der For-Schleife probieren.
 
Hallo,

den Button der das Event auslöst hab ich extra mal ausgenommen, das machte keinen Unterschied. Dispose rufe ich ja nur auf um die Ressourcen freizugeben, das Remove() vorher sollte ja schon dafür sorgen dass das Control verschwindet.

Deine for-Schleife funktioniert, danke dafür, ich denke ich weiß jetzt auch wieso.
Wenn ich schreibe:

C#:
foreach(Control ctrl in this.Controls)
{
    if(ctrl.getType() != typeof(PictureBox))
    {
        MessageBox.Show(ctrl.Text);
    }
}

gibt er mir brav alle meine Controls aus, mit Ausnahme der PictureBox.
Sobald ich aber

C#:
MessageBox.Show(ctrl.Text);

ersetze durch:

C#:
this.Controls.Remove(ctrl);

fehlen die Hälfte der Controls.
Vermutlich kommt er in der foreach Schleife durcheinander wenn man ihm währendessen Controls aus seiner Collection entfernt. Anders kann ichs mir nicht erklären.
Bei deiner for Schleife läuft er starr von vorne nach hinten durch, da kanns ihm ja egal sein wenn was entfernt wird.
Das ist die einzige Begründung die mir jetzt einfallen würde. Seltsam find ichs trotzdem.

Naja egal, geht ja jetzt, danke nochmal für eure Hilfe :)
 
Hallo,

beim Durchlaufen einer foreach- oder for-Schleife Elemente zu löschen, ist immer eine schlechte Idee, weil dann Indizes usw. nicht mehr passen. Mit der while-Schleife müsste es aber gehen:
C#:
int nDelIndex = 0;
while( Controls.Count > nDelIndex )
{
    if( Controls[nDelIndex] is PictureBox )
    {
        nDelIndex++;
    }
    else
    {
        Controls.RemoveAt(nDelIndex);
    }
}
Gruß
MCoder
 
Hallo,

beim Durchlaufen einer foreach- oder for-Schleife Elemente zu löschen, ist immer eine schlechte Idee, weil dann Indizes usw. nicht mehr passen.

Jah, ich hab noch ein wenig rumprobiert und bin dahintergekommen. Wenn in der Schleife etwas aus der Collection entfernt wird, schiebt er sie direkt zusammen um die Lücke zu schließen, dabei kanns passieren das Controls, die noch gar nicht dran waren, aber Indize vorbeirutschen und nie aufgerufen werden.
foreach fällt daher aufjedenfall flach. Mit for geht es, auf 2 Arten:

Entweder so wie es schon im Thread weiter oben steht:

C#:
for(int i = this.Controls.Count - 1; i >= 0; i--)
{
}

weil wenn man rückwärts durchläuft kann er die Lücken gerne zuschieben nach einem remove, weil die Controls die da bewegt werden waren ja schon dran.

Oder aber:

C#:
for(int i = 0; i < this.Controls.Count; i++)
{
    //remove Control
    i--;
}

in dem man den Indize händisch eins zurücksetzt wenn ein Control entfernt wurde, um das Control welches den leeren Platz dann einnimmt nicht zu überlaufen.
Die while Schleife geht natürlich auch.

Hat bei mir nur eine Weile gedauert zu verstehen wieso überhaupt Controls ausgelassen werden, jetzt wo es klar ist tun sich plötzlich viele Möglichkeiten auf das zu lösen :)
 
@rd4eva: Da steht eh ein remove drinnen.
Trotzdem bringtst du mich auf eine gute Idee. Soweit ich weiß darf man bei Collections durch die man mit foreach durchläuft nicht hinzufügen oder entfernen. Also ev. mal die Version mit der For-Schleife probieren.

Hast recht. Das Remove hatte ich einfach überlesen.

Doch. Der Aufruf der Dispose-Methode sorgt dafür, dass das Objekt seine Resourcen freigibt und daher zwangsweise verschwindet.
Nope das ist falsch. Aufruf von Dispose gibt (sofern man den optionalen Parameter weglässt) nur unmanaged Ressourcen frei. Das bedeuetet aber noch lange nicht das ein Control zwangsweise durch Aufruf von Dispose verschwinden muss.
 
Zurück