foreach działa tylko na co 2 element

0

Witam, problem dokładnie taki jak w temacie- pętla foreach usuwa tylko co 2 button które są w panelu. Projekt robiony w winforms

foreach(Control control in panelMapCreate.Controls)
            {
                Controls.Remove(control);
                control.Dispose();
            }

Dodam że wszystkie te buttony są również tworzone podczas działania programu

int wysokosc = Int32.Parse(comboBoxWysokosc.Text);
            int szerokosc = Int32.Parse(comboBoxSzerokosc.Text);
            for (int i = 0; i < wysokosc; i++)
            {
                for (int j = 0; j < szerokosc; j++)
                {
                    Button newButton = new Button();
                    newButton.Location = new Point(4 + 50 * j, 4 + 50 * i);

                    newButton.Height = 40;
                    newButton.Width = 40;
                    panelMapCreate.Controls.Add(newButton);
                    newButton.Show();
                }
            }

Ktoś ma jakiś pomysł?

3

Nie usuwaj elementów kolekcji w foreachu

The foreach statement is used to iterate through the collection to get the information that you want, but can not be used to add or remove items from the source collection to avoid unpredictable side effects. If you need to add or remove items from the source collection, use a for loop.

unpredictable side effects

0

Dzięki, zrobiłem to już while'em.

while (panelMapCreate.Controls.Count>0)
                {
                    Controls.Remove(panelMapCreate.Controls[0]);
                    panelMapCreate.Controls[0].Dispose();
                }

Mam nawet pewną ideę jak to może działać że usuwa tylko co 2 no bo skoro foreach działa na zasadzie iteracji(nie wiem czy tak jest tylko tak zakładam) w momencie kiedy usunie element 0 element 1 staje się 0. Wtedy foreach chce usunąć element początkowo 1 pomijając aktualnie 0 usuwając element który był początkowo 2 itd.
Może ktoś mądry to potwierdzi jeśli mam rację albo obali i poda poprawne wyjaśnienie.
Nie mniej problem rozwiązany(właściwie niepotrzebnie założony wątek), ale jeśli ktoś ma chęci pomyszkować lub zna odpowiedź dlaczego tak się dzieje chętnie się dowiem ;)

4
Foka napisał(a):

Mam nawet pewną ideę jak to może działać że usuwa tylko co 2 no bo skoro foreach działa na zasadzie iteracji(nie wiem czy tak jest tylko tak zakładam) w momencie kiedy usunie element 0 element 1 staje się 0. Wtedy foreach chce usunąć element początkowo 1 pomijając aktualnie 0 usuwając element który był początkowo 2 itd.

Mniej więcej tak, tylko sprawa jest trochę bardziej skomplikowana, bo foreach to tylko taki cukier składniowy do korzystania z Enumeratora: https://www.dotnetperls.com/getenumerator
Czyli generalnie wszystko zależy od implemetacji Enumeratora właśnie, no ale że zazwyczaj w środku jest jakaś tablica, a MoveNext zwiększa po prostu indeks, z którego później korzysta właściwość Current, to jest tak, jak napisałeś - indeksy w foreach idą do przodu, ale na skutek usuwania elementy zmieniają swoje indeksy na mniejsze.

1

Ja tu czegoś chyba nie ogarniam. Iterujesz po panelMapCreate.Controls, a usuwasz z Controls. Te buttony są dodane i do panelMapCreate i do kontrolki w której są te metody? Jeżeli tak, to nie powinno tak być, jeżeli nie to nie powinno to w ogóle działać.

0

No a to nie jest tak że jak dodaje buttona do panelu to jest on jednocześnie dodawany do kolekcji kontrolek panelu i do kolekcji kontrolek całej formy?

0

Generalnie oba poniższe sposoby działają.

Controls.Remove(panelMapCreate.Controls[ilosc]);
 panelMapCreate.Controls[ilosc].Dispose();

i tak

 Control control = panelMapCreate.Controls[ilosc];
 panelMapCreate.Controls.Remove(control);
  control.Dispose();

Pomimo tego że buttony kontrolki które usuwam są tylko w kolekcji panelu. Przynajmniej tak się wydaję gdy sprawdzę ich ilość w ten sposób

labelile.Text = Controls.Count.ToString();
labelile.Text += " " + panelMapCreate.Controls.Count.ToString();
1

Pierwszy przykład jest błędny, bo Dispose wywołujesz na innej kontrolce.

Jeżeli dodajesz je do kolekcji panelu, to tam są i stamtąd powinieneś je usuwać.

0

NIe wiem - nie pamietam jak wyglada Controls ale nie ma to przypadkiem metody .Clear()?

0

"Calling the Clear method does not remove control handles from memory. You must explicitly call the Dispose method to avoid memory leaks." Nie wiem czym dokładnie są handles, ale mimo to nie brzmi to zachęcająco

0

Chodzi o uchwyty do zasobów natywnych, którymi .NET nie zarządza.

1

Jeżeli próbujesz usunąć element z foreach'a to zawsze dostaniesz błąd (chyba że zastosujesz go na Kolekcja.ToList()).

W 1 poście nie dostajesz żadnego błędu tylko dlatego, że iterujesz po "panelMapCreate.Controls" a usuwasz elementy z "Controls" (czemu to ma służyć to nie wiem).

1 użytkowników online, w tym zalogowanych: 0, gości: 1