从父控件/窗体中完全删除控件的正确方法是什么?
我的应用程序中有一个 UI 元素,其中一个面板用于托管多个潜在的自定义用户控件之一。面板本身托管在一个标准化的用户控件中,我使用的是类似非模式对话框的东西,我称之为“窗格”。
我使用的方法是实例化标准窗格的一个新实例,然后使用 Panel.Controls.Add(control)
通过逻辑实例化其中的几个可选托管控件之一。然后,我再次使用 Control.Controls.Add(control)
将新窗格添加到界面控件的设定位置,然后使用 control.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 后仍然存在,并且偶尔仍会出现在屏幕上。
这一切都引出了我最初的问题,在控件达到目的后删除和完全销毁控件的正确方法是什么?
I have a UI element in my application where a Panel is used to host one of several potential custom UserControls. The Panel itself is hosted in a standardised UserControl that I am using something like a non-modal dialog that I'm calling a 'pane'.
The method I use is to instantiate a new instance of the standard pane, then with logic instantiate one of the several optional hosted controls inside it using Panel.Controls.Add(control)
. I then add the new pane to the interface control in a set location, again with a Control.Controls.Add(control)
, followed by a control.BringToFront()
to maximise its z position.
This all works well, however when the time comes to hide the pane and destroy it, I cannot seem to fully get rid of it. Originally I was simply using Control.Controls.Remove(control)
and for good measure setting the pane's Parent property to Nothing. This would have the desired effect of making the pane disappear, and my assumption was that now the control was unreferenced, that GC would dispose of it.
What I am seeing however is that the control still blits instantaneously onto the screen when the next outer hosting TabControl changes tab page, implying it still exists somewhere. I can confirm that this is not a graphical issue and the pane object persists using the VS Watch window's 'Make Object ID'. (At least I think this is proof, that without a code-accessible reference I can still directly see the object and its properties continue to exist.)
I have tried replacing
Control.Controls.Remove(pane)
pane.Parent = Nothing
with
pane.Dispose()
GC.Collect()
where the Dispose call I can confirm both removes the control from its parent's Controls collection and sets its Parent property to Nothing, but appears to do no more. It persists after forced GC and still blits onscreen occasionally.
This all leads to my original question, what is the proper way to remove and fully destroy controls after they have served their purpose?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
根据 MSDN 的 这篇 文章似乎您可能会遇到来自终结队列上的对象的副作用。
翻译:finalize 方法没有被调用,因此与您的控件关联的资源没有被释放。经过更多挖掘后,我发现你应该
来自这篇文章。
因此,您要么需要释放最后一个引用,要么需要直接调用组件的 Finalize 方法,以便 GC.Collect() 能够工作。
According to this article from MSDN it seems like you might be experiencing side affects from the object being on the finalization queue.
Translation: The finalize method isn't being called, and so the resources associated with your control are not being released. After a bit more digging, I found that you should
From this article.
So either you need to release your last reference OR you need to call the components finalize method directly so your GC.Collect() will work.