繁体   English   中英

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

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

在WinForms应用程序中,我有多个实例,在其中我将一个控件添加到容器中以响应用户操作( panel.Controls.Add(new CustomControl(...)) ),然后稍后清除面板( panel.Controls.Clear() )并重新使用它。

在生产中,该应用偶尔会引发与GDI错误或无法加载ImageList有关的异常。 这通常发生在资源有限的计算机上,以及一天中大量使用该应用程序的用户。 很明显,我有一个GDI句柄泄漏,应该处理从容器中清除的控件,但是我发现的任何解释都不清楚应在何时何处放置控件。

我应该在清理容器后立即处置儿童控件吗? 就像是:

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

还是应该在列表中跟踪控件并在容器的Dispose()方法中调用dispose? 如:

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();
}

选项2引入了另一个您需要清除的列表,这些列表将占用更多的内存。 我希望选项1带有围绕您提到的代码的try catch。

在(以某种有效的方式)纠正了我的应用没有处理清除的控件的所有情况后,我可以提出几点:

  • 有时我会预先构建一个控件列表,例如,存储在ListViewItemTreeViewItem的集合的Tag属性中。 它们不应该被清除,但是整个列表应该被迭代,并在父级的Dispose()方法中调用((Control)item.Tag).Dispose()
  • 如果不再使用该控件(当我即时创建它时会发生这种情况),则应在从容器中清除该控件时将其丢弃。
  • 即时清除和添加控件时,您需要考虑控件的生命周期,以确定是否要立即处理它们,将其推迟到处理父对象之前还是不必担心。
  • 我遇到的情况是,我删除了一个控件以显示“正在加载...”消息,然后响应于线程完成而将该控件放回原处。 删除控件时,我添加了一个处置该控件的调用,这在尝试再次添加它时导致错误。 由于存在线程问题,因此调试起来并不容易。 关键是生命周期可以依赖于UI线程以外的线程。 适当的情况是在显示表单后大约20秒,因此至少控件仍然存在。 在弱事件发生的情况下,管理可能被线程仍希望引用的控件破坏的情况。

在管理控制生命周期和处置方面,我找不到任何最佳实践或建议。 我猜规则是,如果一个控件没有结束,那么它的生命就嵌套在一个被处置的控件上,无论何时不再使用它,都必须手动处置它,或者在父控件的Dispose()最晚的方法。

暂无
暂无

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

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