2010-01-06 77 views
6

我有一个程序,增加了一系列的“光点”的一个图:在C#中删除动态创建的控件

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. 如何我有一个按钮清除所有具有“光点”的用这个代码创建的?

  2. 当名称等于某个callsign时,是否有方法更改blip的背景颜色?每个blip都与ListBox中的选择相关联,并且我想在用户选择它时更改blip的颜色。

回答

24

每个人都忘记了一个非常重要细节:你要的Dispose()的控制,否则将永远泄漏:

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

我会放一些更强调永远是子句,在评论中对它有很多的鼓噪,Control类不像任何其他的.NET类。一个控件通过其Handle属性保持活着。其中存储本地Windows句柄。只要本地窗口存在,Control对象就不能被销毁。

这需要在使用Clear()或Remove()并将控件从其父项中移除时人为地保持活动状态。 Winforms使用所谓的“停车窗口”作为这种控件的主机。这是一个普通的本地窗口,就像任何其他窗口一样,它只是不可见。它的工作就是成为这种孤儿控制的母体。

停车窗口允许很多整洁的技巧,通常很难在Windows中完成。例如,您可以在运行时打开和关闭ShowInTaskbar属性。通常只能在创建窗口时指定的窗口属性(在CreateWindowEx()调用中指定的WS_EX_APPWINDOW样式)。即使在创建窗口后,Winforms也可以将窗体的控件移动到停靠窗口,破坏窗口,再次创建窗体并将控件移回。整齐。

但是对于这个答案的主题不太清楚的挂断,如果您删除控件并且不要调用它的Dispose()方法,那么它将继续在停车窗口中生存。永远。真实的泄漏。垃圾收集器无法做到这一点,它会看到对该对象的有效引用。对于IDisposable合同的严重违反,调用Dispose()是可选的,但对于Control类,它不是而是

幸运的是,这样的错误很容易诊断,它不需要任何特殊的工具,您可以在任务管理器的进程选项卡中看到泄漏。添加“USER对象”列。

+1

+ 1 ..感谢,完全忘了。实际上控件的配置方法调用parent.Controls.Remove(this) – 2010-01-06 16:38:37

+1

它不会永远泄漏......它只会在垃圾收集器出现之前泄漏......然后希望PictureBox的析构函数包含对Dispose的调用。 – Nick 2010-01-06 16:38:38

+1

@Stan R - 它呢?很酷......我不知道! – Nick 2010-01-06 16:39:30

4
this.Controls.Clear(); 
+2

可选的,因为控制和动态创建,“清除”按钮,可以简单地只是重建与完全回发的控制没有什么。 – NotMe 2010-01-06 16:16:17

+0

这将删除所有的控件,不管它们是否是PictureBox。 – 2010-01-06 16:17:34

+0

这将清除所有控件。我只想清除创建的“blip”控件。 – Brodie 2010-01-06 16:18:23

2

您可能希望将昙花一现添加到列表中,然后当用户点击“清除”按钮,只需遍历列表,请从控件集合的昙花一现,然后清除列表。

就改变背景颜色而言,为什么不使用if语句?

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

Jonathan Keith提到this.Controls.Clear()可能有效,但取决于(this)的上下文,也可能会清除其他控件。但是,如果上下文允许,乔纳森的答案可能需要少两个时钟周期。 – hackerhasid 2010-01-06 16:15:55

3

这将删除所有来自特定容器中的图片框控件的(ⅰ假设你的情况的曲线图)。

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

       control.Dispose(); 
      } 
0

Hans Passant似乎忘记了一个非常重要的细节(或者他只是增加了现有的答案,没有提交完整的答案)。无论如何,这是我必须做既invisiblize和处置我的动态控制:

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

他忘记了什么是非常重要的细节? – 2017-10-29 16:29:54