如何解决我们什么时候应该为组件实现带有 IContainer 参数的构造函数?
假设我有一个 WinForms 组件。
它可以是基于 System.ComponentModel.Component 或 System.Windows.Forms.Control 类的类(实际上 Control
继承了 Component
)。
我的组件可能会使用我们应该正确处理的其他 .NET 类 - Pens、Brushes、ContextMenuStrips 等。我根据众所周知的 IDisposable 模式在 dispose(bool disposing)
方法的实现中按预期处理它们。
我想知道,当我必须添加一个接受 IConatiner 参数的特殊构造函数时,表单设计器将注册我的组件实例,以便在表单关闭期间自动处理资源:
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
...
this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components);
}
protected override void dispose(bool disposing)
{
if (disposing && (components != null))
{
components.dispose();
}
base.dispose(disposing);
}
我分析了一些WinForms组件的dispose(bool disposing)
方法的源代码试图找到答案,但情况仍然不清楚。
例如,ContextMenuStrip
组件具有这样的构造函数,但 DataGridView
没有 - 尽管它们在 dispose(bool disposing)
实现中都有足够的对象。
有什么提示或想法吗?
解决方法
如果您是组件作者,作为最佳实践,我的建议是实现接受 IContainer
的构造函数重载,因为当组件具有这样的构造函数时,当开发人员在设计图面上放置组件的实例时,设计者生成一段代码,负责处理组件。
-
您的组件在 ToolBox 中可用吗?
对于可以通过工具箱访问的组件,如果用户将组件放在设计器上,那么他们不应该担心组件的处理。所有的标准组件都遵循这种模式,用户从不关心他们通过设计器创建的控件和组件的处置,因此关心设计时支持是组件作者的责任。
-
您的组件中有什么要处理的吗?
如果你没有什么要处理的,那么这个重载不是那么重要,但是如果你有什么要处理的,那么你应该关心处理。正如在前面的要点中提到的,由于用户可能会将您的组件放在设计器上并指望设计器处理它们,那么您有责任提供该方法,以便设计器生成处理代码。否则,组件将不会被释放,从而导致内存/句柄泄漏。
作为组件用户
作为组件用户,如果您在代码中创建组件(而不是在设计时删除它),您有责任在不再需要组件时处理它。您可能会发现这篇文章很有用:Why should I insert a non-UI Windows.Forms component from the designer?
如果您从工具箱中删除了一个组件,那么您无需担心它的处理。所有标准组件生成一个代码o在处理表单时处理组件。
设计者生成的代码如何处理组件的处置?
对于具有接受 IContainer
的构造函数的组件,当您将它们放在设计图面上时,设计器会生成一个代码来创建一个 components
集合并将该组件添加到该集合中,然后处理表单处理时的集合(包括其所有组件)。
查看以下设计器生成的代码:
private System.ComponentModel.IContainer components = null;
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
InitializeComponent()
{
this.components = new System.ComponentModel.Container();
...
...
this.myComponent = new MyComponent(this.components);
...
...
}
还有 Dispose method of Container 类:
protected virtual void Dispose(bool disposing) {
if (disposing) {
lock (syncObj) {
while (siteCount > 0) {
ISite site = sites[--siteCount];
site.Component.Site = null;
site.Component.Dispose();
}
sites = null;
components = null;
}
}
}
你会看到当你的表单被释放时,它会释放它在容器中找到的所有组件。
,不需要使用 IContainer 创建额外的构造函数。如果省略这个,那你就得自己把Control加到IContainer中了。
public void MyForm()
{
InitializeComponents();
this.components.Add(this.MyUserControl);
}
如果你不把这个添加到this.components,你必须显式地Dispose MyUserControl。 额外问题:如果没有人使用 this.components,那么 this.components 仍然为 null。
总而言之,每当您创建一个必须被处置的控件时,添加额外的构造函数的工作量就会减少。毕竟是单线。
public MyUserControl()
{
InitializeComponents();
...
}
public MyUserControl(IContainer container) : this()
{
container?.Add(this);
}
好消息是,visual studio 设计师识别出这个构造函数并将使用它。它甚至会为您创建容器。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。