在 C# 中删除动态创建的控件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2014286/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 22:40:24  来源:igfitidea点击:

Removing dynamically created controls in C#

c#dynamiccontrols

提问by Brodie

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.

  1. 如何让按钮清除使用此代码创建的所有“blips”?

  2. 有没有办法在名称等于某个 blip 时更改 blip 的背景颜色callsign?每个 blip 都与 a 中的一个选择相关联ListBox,我想在用户选择它时更改 blip 的颜色。

采纳答案by Hans Passant

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

每个人都忘记了一个非常重要的细节:你必须对控件进行 Dispose() 否则它会永远泄漏:

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 foreverclause, 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 Handleproperty. Which stores the native Windows handle. As long as the native window exists, the Control object cannot be destroyed.

我将更加强调永远子句,在评论中对其进行了大量讨论,Control 类的行为与任何其他 .NET 类不同。控件通过其Handle属性保持活动状态。它存储本机 Windows 句柄。只要本机窗口存在,就不能销毁 Control 对象。

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.

这需要在您使用 Clear() 或 Remove() 并从其父级中删除控件时人为地使对象保持活动状态。Winforms 使用所谓的“停放窗口”作为此类控件的宿主。它是一个普通的本机窗口,就像其他任何窗口一样,只是不可见。它的工作是成为这种孤立控件的父级。

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.

停车窗提供了许多通常在 Windows 中很难做到的巧妙技巧。例如,您可以在运行时打开和关闭 ShowInTaskbar 属性。通常只能在创建窗口时指定的窗口属性(WS_EX_APPWINDOW 样式,在 CreateWindowEx() 调用中指定)。Winforms 甚至可以通过将窗体的控件移动到停车窗口、销毁窗口、再次创建它并将控件移回来创建窗口来执行此操作。整洁的。

But with the not-so-neat hangup that's the topic of this answer, if you remove the control and don'tcall 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 notfor the Control class.

但是由于不那么整洁的挂断是这个答案的主题,如果您删除控件并且调用其 Dispose() 方法,那么它将继续在停车窗口上存活。永远。真正的泄漏。垃圾收集器对此无能为力,它会看到对对象的有效引用。对 IDisposable 合同的严重违反,调用 Dispose() 是可选的,但它不适用于 Control 类。

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.

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

回答by JonathanK

this.Controls.Clear();

回答by hackerhasid

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.

您可能希望将 blip 添加到列表中,然后当用户单击“清除”按钮时,只需遍历列表,从控件集合中删除 blip,然后清除列表。

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

在更改背景颜色方面,为什么不使用 if 语句?

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

回答by Stan R.

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

这将从特定容器中删除所有 PictureBox 控件(我假设您的情况是一个图形)。

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

                control.Dispose();
            }

回答by B. Clay Shannon

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:

Hans Passant 似乎也忘记了一个非常重要的细节(或者他可能只是在现有答案中添加内容,而不是提交完整答案)。无论如何,这是我必须执行的操作才能隐藏和处理我的动态控件:

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