3

我的应用程序中有一个 UI 元素,其中一个面板用于托管几个潜在的自定义用户控件之一。面板本身托管在一个标准化的用户控件中,我正在使用类似于非模态对话框的东西,我称之为“窗格”。

我使用的方法是实例化标准窗格的新实例,然后使用逻辑实例化其中的几个可选托管控件之一,使用Panel.Controls.Add(control). 然后,我将新窗格添加到设置位置的界面控件,再次使用 a Control.Controls.Add(control),后跟 acontrol.BringToFront()以最大化其 z 位置。

这一切都很好,但是当需要隐藏窗格并销毁它时,我似乎无法完全摆脱它。最初,我只是简单地使用Control.Controls.Remove(control)并很好地将窗格的 Parent 属性设置为 Nothing。这将产生使窗格消失的预期效果,我的假设是现在控件未被引用,GC 将处理它。

然而,我看到的是,当下一个外部托管 TabControl 更改标签页时,该控件仍会立即闪烁到屏幕上,这意味着它仍然存在于某处。我可以确认这不是图形问题,并且窗格对象使用 VS Watch 窗口的“生成对象 ID”仍然存在。(至少我认为这是证明,如果没有代码可访问的引用,我仍然可以直接看到对象及其属性继续存在。)

我试过更换

Control.Controls.Remove(pane)
pane.Parent = Nothing

pane.Dispose()
GC.Collect()

我可以确认 Dispose 调用将控件从其父控件集合中删除并将其 Parent 属性设置为 Nothing,但似乎没有更多操作。它在强制 GC 后仍然存在,并且偶尔仍会在屏幕上闪烁。

这一切都导致了我最初的问题,在它们达到目的后删除和完全销毁控件的正确方法是什么?

4

1 回答 1

0

根据 MSDN 上的这篇文章,您似乎可能会遇到来自完成队列上的对象的副作用。

Dispose 方法应该为它正在处理的对象调用 GC.SuppressFinalize 方法。如果对象当前在终结队列中,GC.SuppressFinalize 会阻止调用其 Finalize 方法。

翻译:finalize 方法没有被调用,因此与您的控件关联的资源没有被释放。经过多一点挖掘,我发现你应该

在发布对组件的最后引用之前,请始终调用 Dispose。否则,在垃圾收集器调用 Component 对象的 Finalize 方法之前,它正在使用的资源不会被释放。

这篇文章。

所以要么你需要释放你的最后一个引用,要么你需要直接调用组件的 finalize 方法,这样你的 GC.Collect() 才能工作。

于 2013-06-20T16:42:19.720 回答