简体   繁体   English

清除容器的Controls属性并确保正确处置控件的最安全方法是什么?

[英]What is the safest way to clear a container's Controls property and make sure the controls are properly disposed?

In a WinForms application I have a number of instances where I add a control to a container in response to a user action ( panel.Controls.Add(new CustomControl(...)) ), then later clear the panel ( panel.Controls.Clear() ) and reuse it. 在WinForms应用程序中,我有多个实例,在其中我将一个控件添加到容器中以响应用户操作( panel.Controls.Add(new CustomControl(...)) ),然后稍后清除面板( panel.Controls.Clear() )并重新使用它。

In production, the app occasionally throws an exception relating to GDI errors or failing to load an ImageList . 在生产中,该应用偶尔会引发与GDI错误或无法加载ImageList有关的异常。 This usually happens on machines with limited resources and with users that use the application intensively over the day. 这通常发生在资源有限的计算机上,以及一天中大量使用该应用程序的用户。 It seems pretty obvious that I have a GDI handle leak and that I should be disposing the controls that get cleared from the container, however any explanations I can find are vague about where and when the control should be disposed. 很明显,我有一个GDI句柄泄漏,应该处理从容器中清除的控件,但是我发现的任何解释都不清楚应在何时何处放置控件。

Should I dispose the child controls immediately after clearing the container? 我应该在清理容器后立即处置儿童控件吗? Something like: 就像是:

var controls = new List<Control>(_panel.Controls.Cast<Control>());
_panel.Controls.Clear();
foreach (var c in controls) c.Dispose();

Or should I track the controls in a list and call dispose in the container's Dispose() method? 还是应该在列表中跟踪控件并在容器的Dispose()方法中调用dispose? Such as: 如:

List<Control> _controlsToDispose = new List<Control>();
void ClearControls()
{
    _controlsToDispose.AddRange(_panel.Controls.Cast<Control>());
    _panel.Controls.Clear();
}
void Dispose()
{
    ...
    foreach (var c in _controlsToDispose) c.Dispose();
}

Option 2 introduces another list which you would need to cleanup and it will take some more memory for those items. 选项2引入了另一个您需要清除的列表,这些列表将占用更多的内存。 I would prefer option 1 with a try catch wrapped around the code you mentioned. 我希望选项1带有围绕您提到的代码的try catch。

After (somewhat effectively) correcting any cases where my app wasn't disposing cleared controls I can come up with some points: 在(以某种有效的方式)纠正了我的应用没有处理清除的控件的所有情况后,我可以提出几点:

  • Sometimes I've pre-built a list of controls, stored for example in the Tag property of a collection of ListViewItem s or TreeViewItem s. 有时我会预先构建一个控件列表,例如,存储在ListViewItemTreeViewItem的集合的Tag属性中。 They shouldn't be disposed on clear, but the entire list should be iterated and ((Control)item.Tag).Dispose() called in the parent's Dispose() method. 它们不应该被清除,但是整个列表应该被迭代,并在父级的Dispose()方法中调用((Control)item.Tag).Dispose()
  • If the control isn't going to be used again, which can happen when I create it on the fly, it should be disposed when it is cleared from the container. 如果不再使用该控件(当我即时创建它时会发生这种情况),则应在从容器中清除该控件时将其丢弃。
  • When clearing and adding controls on the fly you need to consider the lifecycle of the controls to determine whether to dispose them immediately, defer it until the parent is being disposed, or to not worry about it. 即时清除和添加控件时,您需要考虑控件的生命周期,以确定是否要立即处理它们,将其推迟到处理父对象之前还是不必担心。
  • I had a situation where I removed a control to display a 'Loading...' message, then dropped the control back in later, in response to a thread completing. 我遇到的情况是,我删除了一个控件以显示“正在加载...”消息,然后响应于线程完成而将该控件放回原处。 I added a call to dispose the control when I removed it, which caused errors when trying to add it again. 删除控件时,我添加了一个处置该控件的调用,这在尝试再次添加它时导致错误。 Because of the threading issue it wasn't straightforward to debug. 由于存在线程问题,因此调试起来并不容易。 The point is that the lifecycle can depend on threads other than the UI thread. 关键是生命周期可以依赖于UI线程以外的线程。 The case in point was a matter of 20 seconds after the form was displayed, so at least the control still existed. 适当的情况是在显示表单后大约20秒,因此至少控件仍然存在。 Managing a situation where a control can be destroyed with threads still wanting to refer to it is probably a case for weak events. 在弱事件发生的情况下,管理可能被线程仍希望引用的控件破坏的情况。

I haven't been able to find any best practices or recommendations on managing control lifecycle and disposal. 在管理控制生命周期和处置方面,我找不到任何最佳实践或建议。 I guess the rule is just that if a control doesn't end it's life nested on a control that is disposed, it has to be disposed manually, whenever it isn't going to be used again, or in the parent control's Dispose() method at the latest. 我猜规则是,如果一个控件没有结束,那么它的生命就嵌套在一个被处置的控件上,无论何时不再使用它,都必须手动处置它,或者在父控件的Dispose()最晚的方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM