【问题标题】:.NET (non-visual) component.NET(非可视)组件
【发布时间】:2011-05-10 20:21:12
【问题描述】:

我需要创建一个非可视组件FooComponent,它将对其表单中所有Bar 类型的控件进行一些管理。

我有以下限制:

  1. FooComponent 只能添加到表单中。
  2. 每个表单只允许一个FooComponent
  3. FooComponent 应该注册到表单关闭事件,并在它触发时注册到所有 Bar 上的某个函数,并根据返回的值发送 e.Cancel 值。

上面的#1 和#2 应该在运行时和设计时强制执行。 #3 事件注册应自动进行,而不是由FooComponent 的用户进行。

我在 Google 和 MSDN 中搜索了一些帮助并阅读了有关 ComponentComponentDesigner 课程的信息,但我没有找到任何可以挽救的信息。

我该怎么办?

【问题讨论】:

标签: c# .net visual-studio winforms


【解决方案1】:

(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() 中,您可以访问SiteContainer 等属性。同样,您只会在运行时而不是设计时得到它,并且在这里抛出异常不会阻止组件的创建。

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 帮助文件。您需要在文件的属性页面中取消阻止才能在下载后读取内容。

【讨论】:

  • 不允许空构造函数的缺点是您将无法在设计时使用控件。
  • OP 说这是他正在创建的非可视组件,所以这应该不是问题。我的意思是构造函数是 FooComponent 构造函数......我会在问题中澄清这一点
  • 我明白你的意思......如果他的字面意思是Component,他想在表单中拖放,那么你是对的,他必须有一个默认构造函数。跨度>
  • 感谢您的回答,但我确实需要默认构造函数才能将组件放到表单上。
  • 谢谢你的回答,我会复习文章的。
【解决方案2】:

我认为不可能准确定义包含的类可以包含在其中的内容。我当然从未见过这样的例子:我在设置一种类型的属性时遇到错误(甚至是警告),即使在 WinForms 中也是如此。

您可以做的事情是为您的表单定义一个源自表单的祖先,其中包含对您的(内部可见的)FooComponent 的引用,在实例化时初始化一个,并附加处理程序。为了获得最佳结果,它应该是无参数的并且是唯一的构造函数重载,因此它构成了消费者提出的任何构造函数的基础。然后,只需将表单从您的祖先类派生而不是直接从 Form 派生为家规(当代码提交到源代码管理时,您可能可以使用 FxCop 或类似的代码检查工具来强制执行此操作)。您的用户现在在他们创建的每个 Form 中都获得一个 FooComponent ,不能创建自己的(它是内部的,应该与您的 Form 祖先在另一个项目中)并且除了从新类派生以使他们的表单行为之外不需要做任何事情你想要的方式。

【讨论】:

  • 我需要在设计时支持这个,你知道无论如何要在设计时实现#3吗?
【解决方案3】:

你要求很多。一般来说,让组件知道它们被丢弃的形式是相当困难的。 This answer 可以帮助您实现事件处理程序。您需要实现 ISupportInitialize 以获取 EndInit() 调用以设置事件处理程序。

防止倍数也很困难,我只能想到一个自定义设计器,可以尽早介入以防止添加第二个。

【讨论】:

    猜你喜欢
    • 2010-09-08
    • 2011-02-01
    • 2011-03-20
    • 2012-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-07
    相关资源
    最近更新 更多