清除容器的控件属性并确保正确处置控件的最安全方法是什么?
在 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();
}
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.
In production, the app occasionally throws an exception relating to GDI errors or failing to load an 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.
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? 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();
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
选项 2 引入了另一个您需要清理的列表,并且这些项目将占用更多内存。我更喜欢选项 1,并在您提到的代码周围加上 try catch。
Option 2 introduces another list which you would need to cleanup and it will take some more memory for those items. I would prefer option 1 with a try catch wrapped around the code you mentioned.
在(某种程度上有效地)纠正我的应用程序未处理清除控件的任何情况后,我可以得出一些要点:
Tag
中ListViewItem
或TreeViewItem
集合的属性。它们不应该被清除,但应该迭代整个列表并在父级的Dispose()
中调用((Control)item.Tag).Dispose()
方法。我无法找到任何有关管理控制生命周期和处置的最佳实践或建议。我猜规则是,如果一个控件没有结束它嵌套在已处置的控件上的生命,则无论何时不再使用它,或者在父控件的
中,都必须手动处置它最迟使用 Dispose()
方法。After (somewhat effectively) correcting any cases where my app wasn't disposing cleared controls I can come up with some points:
Tag
property of a collection ofListViewItem
s orTreeViewItem
s. They shouldn't be disposed on clear, but the entire list should be iterated and((Control)item.Tag).Dispose()
called in the parent'sDispose()
method.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.