我有以下约束:
> FooComponent只能添加到表单中.
>每个表单只允许一个FooComponent.
> FooComponent应该注册到表单结束事件,当它触发所有Bar的某个函数时,并根据返回的值发送e.Cancel值.
上面的#1和#2应该在运行时和设计时强制执行.
#3事件注册应自动进行,而不是由FooComponent的用户进行.
我在Google和MSDN上搜索了一些帮助,并阅读了有关Component和ComponentDesigner类的内容,但是我找不到任何有关救援的信息.
我该怎么办?
解决方法
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)删除组件不会将组件添加到表单中,而是将其添加到表单的组件集合中.因此,即使您可以获得父母/所有者的句柄,它也永远不会成为表格.
(2)正如Neil指出的那样,将一个组件放到一个表单上会调用默认的构造函数,该构造函数不传递任何参数,当然,也不会填充组件的所有属性(例如站点或容器).
可能有用:组件可以设计为在以几种方式创建时得到通知:
(1)通过实现一个带有IContainer参数的构造函数.当组件被放在表单上时,生成的代码将调用此构造函数.但是,它只会在运行时执行此操作,而不是设计时.但容器将是表单组件集合的句柄.
public FooComponent(IContainer container) {...}
(2)通过实现ISupportInitialize.当组件被放在表单上时,生成的代码将另外调用BeginInit()和EndInit().在EndInit()中,您可以访问诸如“站点”和“容器”之类的属性.同样,您只能在运行时获取此信息,而不是设计时间,并且在此处抛出异常不会阻止创建组件.
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