C# .NET(非可视)组件
我需要创建一个非可视组件,C# .NET(非可视)组件,c#,.net,visual-studio,winforms,C#,.net,Visual Studio,Winforms,我需要创建一个非可视组件,FooComponent,它将对驻留在其表单中的所有Bar类型的控件进行一些管理 我有以下限制: FooComponent只能添加到表单中 每个表单只允许一个FooComponent FooComponent应该注册到表单关闭事件,当它触发时,注册到所有栏上的某个函数,并根据返回的值发送e.Cancel值 #上述1和#2应在运行时和设计时执行。 #3事件注册应自动进行,而不是由FooComponent的用户进行 我在Google和MSDN上搜索了一些帮助,并阅读了Com
FooComponent
,它将对驻留在其表单中的所有Bar
类型的控件进行一些管理
我有以下限制:
FooComponent
只能添加到表单中FooComponent
FooComponent
应该注册到表单关闭事件,当它触发时,注册到所有栏上的某个函数,并根据返回的值发送e.Cancel
值
FooComponent
的用户进行
我在Google和MSDN上搜索了一些帮助,并阅读了Component
和ComponentDesigner
类,但我没有找到任何帮助
我该怎么办?我认为不可能准确地定义包含在其中的类。我当然从未见过在另一种类型(甚至WinForms)中设置一个属性时出现错误(甚至警告)的实例 您可以为表单定义一个表单派生的祖先,该祖先包含对(内部可见)FooComponent的引用,在实例化时初始化一个,并附加处理程序。为了获得最佳结果,它应该是无参数的,并且是唯一的构造函数重载,因此它构成了您的消费者提出的任何构造函数的基础。然后,将表单从您的祖先类派生而不是直接从表单派生作为内部规则(当代码提交到源代码控制时,您可以使用类似于FxCop的代码检查工具来强制执行这一点)。您的用户现在在他们创建的每个表单中都会得到一个FooComponent,不能创建自己的表单(它是内部的,应该在与表单祖先的另一个项目中),并且不必执行任何操作,只需从新类派生即可使其表单按照您希望的方式运行。(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,那么就没有办法强制只在表单上创建一个组件,或者表单只有一个组件实例(无论如何,不是从组件内创建的) 问题有两方面:
(1) 删除组件不会将组件添加到表单中,而是将其添加到表单的
components
集合中。因此,即使您可以获得父/所有者的句柄,它也永远不会是表单
(2) 正如Neil指出的,将组件拖放到表单上会调用默认构造函数,默认构造函数不传递任何参数,当然,也不会填充组件的任何属性(如站点或容器)
可能有帮助:组件可以设计为在通过以下几种方式创建时收到通知:
(1) 通过实现一个接受
IContainer
参数的构造函数。当组件被放到表单上时,生成的代码将调用此构造函数。但是,它只会在运行时执行此操作,而不会在设计时执行。但是容器将是表单的组件的句柄
public FooComponent(IContainer container) {...}
(2) 通过实施ISupportInitialize
。当组件被放到表单上时,生成的代码将另外调用BeginInit()
和EndInit()
。在EndInit()
中,您可以访问属性,例如站点
和容器
。同样,您只会在运行时得到这个结果,而不是在设计时,在这里抛出异常不会阻止组件的创建
Michael Weinhardt和Chris撰写的关于组件和控件的古老但优秀的文章很畅销。
这些现在是.chm帮助文件。您需要在文件的属性页中取消阻止,以便在下载后能够读取内容。您的要求很高。一般来说,让组件知道它们被丢弃的形式是相当困难的。可以帮助您实现事件处理程序。您需要实现ISupportInitialize来获取EndInit()调用以设置事件处理程序
防止多次重复也很难,我只能想到一个自定义设计器,它可以足够早地介入,以防止添加第二次重复。我需要在设计时支持这一点,你知道如何在设计时实现#3吗?不允许空构造函数的缺点是,你将无法在设计时使用控件。OP说他正在创建一个非可视组件,所以这不应该是一个问题。我的意思是构造器是组件构造器。。。我会在问题中澄清我明白你的意思。。。如果他字面上的意思是一个组件
,他想在表单上拖放,那么你是对的,他必须有一个默认构造函数。谢谢你的回答,但我确实需要默认构造函数才能将组件拖放到表单上。谢谢你的回答,我将浏览这篇文章。我想你可以看看CodeDomSerializer()。这可能是你最好的选择。