Удаление динамически созданных элементов управления в С#

У меня есть программа, которая добавляет серию "блипов" к графику:

PictureBox blip = new PictureBox();
blip.Location = new Point(blipHours, blipAltitude);
blip.Size = new Size(6, 6);
blip.BackColor = System.Drawing.Color.Lime;
blip.Text = "";
blip.Name = callsign;
this.Controls.Add(blip);
this.Controls.SetChildIndex(blip, 0);
  • Как у меня есть кнопка очистить все "блики", созданные с помощью этого кода?

  • Есть ли способ изменить цвет фона бэка, когда его имя равно определенному callsign? Каждый сбой связан с выбором в ListBox, и я бы хотел изменить цвет всплытия, когда пользователь его выбирает.

5 ответов

Все забывают важную деталь очень: вам нужно Dispose() элемент управления или он просочится навсегда:

for (int ix = this.Controls.Count - 1; ix >= 0; ix--) {
 if (this.Controls[ix] is PictureBox) this.Controls[ix].Dispose();
}

Я добавлю больше внимания на предложение forever, в комментариях будет много шума, класс Control не будет вести себя как любой другой класс .NET. Элемент управления сохранен в своем свойстве Handle. В котором хранится собственный дескриптор Windows. Пока существует собственное окно, объект Control не может быть уничтожен.

Это требует, чтобы объект поддерживался искусственно, когда вы используете Clear() или Remove() и удаляете элемент управления из его родителя. Winforms использует так называемое "парковочное окно" в качестве узла таких элементов управления. Это нормальное собственное окно, как и любое другое, оно просто не видно. Его задача - быть родителем таких сиротских контролей.

Окно парковки допускает множество аккуратных трюков, которые обычно очень сложно сделать в Windows. Вы можете, например, включить и отключить свойство ShowInTaskbar во время выполнения. Свойство окна, которое обычно можно указывать только при создании окна (стиль WS_EX_APPWINDOW, указанный в вызове CreateWindowEx()). Winforms могут сделать это даже после создания окна, перемещая элементы управления формы в окно парковки, уничтожая окно, создавая его снова и перемещая элементы управления обратно. Ухоженная.

Но при не очень аккуратном зависании в теме ответа, если вы удалите элемент управления и не назовете его метод Dispose(), он продолжит выживать в окне парковки. Навсегда. Истинная утечка. Ничто из того, что сборщик мусора не может сделать с этим, видит правильную ссылку на объект. Довольно грубое нарушение договора IDisposable, вызывающего Dispose(), является необязательным, но оно не относится к классу Control.

К счастью, такая ошибка довольно проста для диагностики, она не требует специальных инструментов, вы можете увидеть утечку на вкладке "Диспетчер задач". Добавьте столбец "USER Objects".


this.Controls.Clear();


Это приведет к удалению всех элементов управления PictureBox из конкретного контейнера (я предполагаю, что график в вашем случае).

for (int i = this.Controls.Count - 1; i >= 0; i--)
 {
 PictureBox control = this.Controls[i] as PictureBox;
 if (control == null)
 continue;
 control.Dispose();
 }


Возможно, вы захотите добавить спам в список, а затем, когда пользователь нажмет кнопку "Очистить", просто перейдя по списку, удалите всплывающее окно из коллекции "Элементы управления", затем очистите список.

Что касается изменения цвета фона, почему бы вам просто не использовать оператор if?

blip.BackColor = callsign == "SpecialSign"? System.Drawing.Color.Red : System.Drawing.Color.Lime


Кажется, Ханс Пассант тоже забыл очень важную деталь (или, может быть, он просто добавлял к существующим ответам, а не отправлял полный ответ). Во всяком случае, вот что мне нужно было сделать для того, чтобы invisiblize и использовать мои динамические элементы управления:

Panel p = tp.Controls[panelName] as Panel;
p.Controls.Clear();
for (int i = 0; i < p.Controls.Count; i++)
{
 p.Controls[i].Dispose();
}

licensed under cc by-sa 3.0 with attribution.