(1) 要控制组件只能添加到表单,请使用传递表单的FooComponent 构造函数,并且不要定义默认构造函数。它被称为:
FooComponent component = new FooComponent(this);
组件是从表单本身创建的。通过不定义默认构造函数,这样:
FooComponent component = new FooComponent();
不会编译。
(2) 在表单本身上暴露一个FooComponent 属性,并在FooComponent 的构造函数中,将传递的表单的FooComponent 设置为this。
(3) 同样的,在FooComponent的构造函数中,为你传递的表单注册关闭事件
把它们放在一起,你会得到:
public class MyForm : Form {
public FooComponent OwnedComponent { get; set; }
}
public class FooComponent {
public FooComponent (MyForm OwnerForm) {
OwnerForm.OwnedComponent = this;
OwnerForm.FormClosing += MyCallback;
}
private void MyCallback(object sender, FormClosingEventArgs e) {
...
}
}
编辑
不幸的是,如果您需要默认构造函数,并且它必须是真正的 drop-on-the-form 组件,则无法强制仅在 Form 上创建组件,或者 Form 只有一个实例组件(无论如何,不是来自组件内部)。
问题是双重的:
(1) 删除组件不会将该组件添加到表单中,而是将其添加到表单的components 集合中。因此,即使您可以获得父/所有者的句柄,它也永远不会是表单。
(2) 正如 Neil 所指出的,将组件拖放到表单上会调用默认构造函数,该构造函数不传递任何参数,当然也不会填充组件的任何属性(例如站点或容器)。
可能有帮助:可以通过以下几种方式将组件设计为在创建时收到通知:
(1) 通过实现一个带有IContainer 参数的构造函数。当组件被拖放到表单上时,生成的代码将改为调用此构造函数。但是,它只会在运行时执行此操作,而不是在设计时执行此操作。但容器将是表单的components 集合的句柄。
public FooComponent(IContainer container) {...}
(2) 通过实现ISupportInitialize。当组件被拖放到表单上时,生成的代码将额外调用BeginInit() 和EndInit()。在EndInit() 中,您可以访问Site 和Container 等属性。同样,您只会在运行时而不是设计时得到它,并且在这里抛出异常不会阻止组件的创建。
Michael Weinhardt 和 Chris Sells 的 MSDN Magazine 上关于组件和控件的旧文章,但非常出色。
April 2003 Building Windows Forms Controls and Components with Rich Design-Time Features
May 2003 Building Windows Forms Controls and Components with Rich Design-Time Features, Part 2
这些现在是 .chm 帮助文件。您需要在文件的属性页面中取消阻止才能在下载后读取内容。