【问题标题】:Is disposing a panel equivalent to disposing its children plus itself?处置面板是否等同于处置其子项和自身?
【发布时间】:2011-02-04 04:18:52
【问题描述】:

在以下类别中:

class MyPanel : Panel
{
    ...
    protected override void Dispose(bool disposing)
    {
        // My code here
    }
}

以下两个代码示例是否等效?

base.Dispose(disposing);

if (disposing)
{
    List<Control> ctrls = new List<Control>(this.Controls);
    this.Controls.Clear();  
    foreach(Control c in ctrls)
    {
         c.Dispose();
    }
}
base.Dispose(disposing);

如果它们有不同的效果,会是什么?

编辑:我问这个是因为,无论出于何种原因,第一种方法会在我的程序处理任何子程序之前冻结我的程序(disposing 是真的,Controls 包含2 个控件),而第二种方法可以正常工作。如果我能愉快地使用第二个,那就太好了。

【问题讨论】:

  • 逻辑上是相同的,通常情况下,结果相同。 Clear() 调用将控制窗口移动到停放窗口。这个(线程)错误有一天会以另一种方式破坏你的后端。
  • @Joe:我很确定我们说的是同一件事。如果子面板仍在运行并生成事件,则很明显您正在泄漏事件处理程序。这并不意味着第二种方法更好,这意味着您需要正确管理您的对象。
  • @Cody,你是对的。我刚刚意识到,当我查看代码时,我正在做的是遍历我的演示者(按视图)并处理它们,从而处理事件处理程序。我不会处理视图上的每个按钮和文本框,那会很愚蠢,因此撤回了我的第一条评论。顺便说一句,我不是那个评论你的答案的乔,那是一个冒名顶替者!

标签: c# .net winforms controls dispose


【解决方案1】:

是的,释放容器将自动释放其子控件。

根据MSDN documentationControl.Dispose方法:

释放控件及其子控件使用的非托管资源,并可选择释放托管资源。

因此在Panel 控件上调用Dispose 方法将自动释放其子控件。但是,正如 Joe 的评论所指出的,对此有一个重要的警告:子控件必须取消订阅在父范围之外声明的事件。如果事件是将保持活动状态的对象的成员,它们将使子控件也保持活动状态并阻止它们被正确处理。显然,您不需要取消订阅在同时被释放的对象(例如父对象)中声明的事件。

当然,将其扩展到Panel 控件的容器(很可能是Form 控件)也毫无价值。每当您 Dispose 拥有 PanelForm 时,Panel 控件及其所有子控件都将自动为您处置。没有理由为 Panel 控件明确地这样做,除非您动态地在表单中添加和删除实例。

【讨论】:

  • 这很有趣。 “拥有面板”是什么意思,因为我所做的是创建一个控件,然后将其添加到表单中。使用这种方法,如果我要处理表单,添加的控件上的计时器将继续触发。我猜这里的关键是所有权,你如何让父母拥有一个没有在表单的 Designer.cs 文件中声明的孩子。
  • @Joe:当你说“计时器”时,你已经把扳手扔进了东西里。您是如何将计时器添加到控件中的?不能保证当控件本身被释放时定时器会被释放,因为它们不一定由控件拥有
  • 嗯...我的计时器是从添加到表单的控件中的构造函数创建的。所以那里不应该有范围界定问题......
  • @Cody - 你知道在第一个例子中它是否会做任何额外的事情吗?
  • @Smashery:我不确定我是否明白你的意思。第一个例子是什么?什么样的额外的东西?没有什么神奇的事情发生。
【解决方案2】:

两者并不相同,您可以通过使用 Reflector 查看 Control.Dispose 的实现来轻松看到(虽然它仍然免费,但很容易做到!)

例如,如果您只是在面板上调用 Dispose,它会在每个子控件上调用 DisposeAxControls,并在对其子控件调用 Dispose 之前将自己从其父控件中移除。

尽管如此,我同意 Cody Gray 的观点 - 你需要弄清楚它为什么会冻结,而不是试图用你提出的解决方法“把问题扫到地毯下”。

通常您不会在面板上显式调用 Dispose - 如果这样做,您需要确保正确管理控件的生命周期和所有权。

要做的事情是开始逐步简化您的应用程序,直到它不再冻结 - 找出导致冻结的原因(例如,通过逐一删除您提到的计时器 - 这听起来很可疑)。一旦你有一个非常简单的例子来展示问题,你(或这里的某人)就会更容易弄清楚发生了什么。

【讨论】:

    猜你喜欢
    • 2012-04-13
    • 1970-01-01
    • 2011-03-31
    • 2011-08-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-28
    • 2014-08-10
    相关资源
    最近更新 更多