By Brodie


2010-01-06 16:09:19 8 Comments

I have a program that adds a series of "blips" to a graph:

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);
  1. How do I have a button clear all of the "blips" that have been created with this code?

  2. Is there a way to change a blip's background color when its name is equal to a certain callsign? Each blip is associated with a selection in a ListBox, and I would like to change the blip's color when the user selects it.

5 comments

@Hans Passant 2010-01-06 16:28:48

Everybody is forgetting a very important detail: you have to Dispose() the control or it will leak forever:

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

I'll put some more emphasis on the forever clause, lots of clamor about it in the comments, the Control class does not behave like any other .NET class. A Control is kept alive by its Handle property. Which stores the native Windows handle. As long as the native window exists, the Control object cannot be destroyed.

This requires the object to be kept alive artificially when you use Clear() or Remove() and remove the control from its parent. Winforms uses the so-called "parking window" as the host of such controls. It is a normal native window like any other, it is just not visible. Its job is to be the parent of such orphaned controls.

The parking window permits lots of neat tricks that are normally very hard to do in Windows. You can for example turn the ShowInTaskbar property on and off at runtime. A property of a window that can normally only be specified when you create the window (WS_EX_APPWINDOW style, specified in the CreateWindowEx() call). Winforms can do it even after you created the window by moving the controls of the form to the parking window, destroying the window, creating it again and moving the controls back. Neat.

But with the not-so-neat hangup that's the topic of this answer, if you remove the control and don't call its Dispose() method then it will continue to survive on the parking window. Forever. A true leak. Nothing that the garbage collector can do about it, it sees a valid reference to the object. A pretty gross violation of the IDisposable contract, calling Dispose() is optional but it is not for the Control class.

Luckily such a bug is pretty easy to diagnose, it doesn't require any special tooling, you can see the leak in Task Manager's Processes tab. Add the "USER Objects" column.

@Stan R. 2010-01-06 16:38:37

+1..thanks for that, completely forgot. in fact controls disposing method calls parent.Controls.Remove(this)

@Nick 2010-01-06 16:38:38

It won't leak forever... it will just leak until the Garbage collector comes around... and then hopefully the destructor for PictureBox includes a call to Dispose.

@Nick 2010-01-06 16:39:30

@Stan R - It does? Cool... I did not know that!

@Hans Passant 2010-01-06 16:46:42

It doesn't. Controls are kept alive by their Handle property. The native window will stay around, it just isn't visible.

@Stan R. 2010-01-06 16:50:33

@nobugz, it doesn't what?

@Dirk Vollmar 2010-01-06 16:58:08

+1, and Dispose will also automatically remove the control from the container's control collection (that's why the list iterates down). Btw, you answered this even better here: stackoverflow.com/questions/1969705/… ;-)

@Hans Passant 2010-01-06 17:05:58

@divo: couldn't use it, only picture boxes were to be removed.

@Hans Passant 2010-01-06 17:07:40

@stan: it doesn't == garbage collector won't clean it up, the control is referenced.

@Stan R. 2010-01-06 17:15:27

@nobugz, oh ok. i thought you were saying it doesn't remove itself from the parent.

@B. Clay Shannon 2014-05-30 23:20:19

It seems Hans Passant forgot a very important detail, too (or perhaps he was just adding to the existing answers, not submitting a full answer). At any rate, here's what I had to do both to invisiblize and dispose my dynamic controls:

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

@Peter Mortensen 2017-10-29 16:29:54

What was the very important detail he forgot?

@Stan R. 2010-01-06 16:17:04

This will remove all of the PictureBox controls from the particular container (i assume a graph in your case).

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

                control.Dispose();
            }

@hackerhasid 2010-01-06 16:13:36

You might want to add the blip to a List and then when the user clicks the "Clear" button, just iterate over the list, remove the blip from the Controls collection, then clear the list.

In terms of changing the background color, why don't you just use an if statement?

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

@hackerhasid 2010-01-06 16:15:55

Jonathan Keith mentioned this.Controls.Clear() which may work, but depending on the context (of "this"), might clear other controls too. If the context permits, however, Jonathan's answer may take a couple less clock cycles.

@JonathanK 2010-01-06 16:12:28

this.Controls.Clear();

@NotMe 2010-01-06 16:16:17

Optionally, because the controls are dynamically created, the "Clear" button could simply just rebuild the control on a full postback with nothing in it.

@Stan R. 2010-01-06 16:17:34

this will remove all of the controls, regardless of whether they are PictureBox or not.

@Brodie 2010-01-06 16:18:23

this clears all controls. I just want to clear the "blip" controls that were created.

@JonathanK 2010-01-06 16:22:28

Yes the context of 'this' in the example is unclear. The solution Stan has posted seems fitting for the context that is now implied. You may consider wrapping this in a UserControl, in which case removing all controls from the this.Controls collection with the Clear() method becomes viable.

Related Questions

Sponsored Content

28 Answered Questions

[SOLVED] How do I generate a random int number?

  • 2010-04-24 23:09:11
  • Rella
  • 1936002 View
  • 1634 Score
  • 28 Answer
  • Tags:   c# random

26 Answered Questions

[SOLVED] How do I enumerate an enum in C#?

296 Answered Questions

[SOLVED] Hidden Features of C#?

  • 2008-08-12 16:32:24
  • Serhat Ozgel
  • 649707 View
  • 1476 Score
  • 296 Answer
  • Tags:   c# hidden-features

24 Answered Questions

[SOLVED] Cast int to enum in C#

  • 2008-08-27 03:58:21
  • lomaxx
  • 1136368 View
  • 2792 Score
  • 24 Answer
  • Tags:   c# enums casting

42 Answered Questions

[SOLVED] How to create Excel (.XLS and .XLSX) file in C# without installing Ms Office?

  • 2008-09-29 22:30:28
  • mistrmark
  • 979295 View
  • 1692 Score
  • 42 Answer
  • Tags:   c# .net excel file-io

38 Answered Questions

57 Answered Questions

[SOLVED] What is the difference between String and string in C#?

9 Answered Questions

[SOLVED] What are the correct version numbers for C#?

24 Answered Questions

[SOLVED] Deserialize JSON into C# dynamic object?

63 Answered Questions

[SOLVED] How do I calculate someone's age in C#?

  • 2008-07-31 23:40:59
  • Jeff Atwood
  • 522877 View
  • 1743 Score
  • 63 Answer
  • Tags:   c# .net datetime

Sponsored Content