4

我正在开发自己的 WinForms 设计器。它必须能够加载现有的自定义表单类型。我遇到的问题之一是没有默认 ctor 的表单:我的代码当前实例化了表单,然后才能将其加载到设计器中,这需要默认 ctor。

OTOH,VS2008 能够加载这样的表格。我相信它实际上并没有实例化我的表单(如本问题所述):即使是默认的ctors也不会被执行。它并没有真正执行 InitializeComponent()。我刚刚在该函数中添加了一个消息框,但它没有显示。

看起来它动态地模仿了自定义表单类型,并且只执行了 InitializeComponent 中它认为相关的部分代码。

有谁知道我在哪里可以找到有关 VS 设计器如何工作的更多信息。

TIA。

注意:我发现这个相关问题没有令人满意的答案

编辑:附加信息:史蒂夫将我指向 CodeDom,这非常有趣。不过,我的问题是我需要加载到我的设计器中的类型已经编译,而不是作为源代码提供。我找不到任何方法将 CodeDom 反序列化应用于已编译的代码。

4

2 回答 2

13

在这里找到这个:

当您在 VS 中打开一个新的 Windows 应用程序项目时,您会在设计视图中看到一个名为 Form1 的空窗体。现在,您还没有构建项目,那么设计人员如何能够创建 Form1 的实例并显示它呢?好吧,设计器根本没有真正实例化 Form1。它正在创建Form1 基类的一个实例,即System.Windows.Forms.Form。有了面向对象编程的基本知识,您会发现这在直觉上是有道理的。在设计 Form1 时,您从基类 Form 开始,并对其进行自定义。这正是设计师帮助你做的事情。

现在假设您向窗体添加了一堆控件并关闭了设计器。当您重新打开设计器时,控件仍然存在。但是基类Form上并没有这些控件,所以如果设计者没有运行Form1的构造函数,它是如何显示控件的呢?设计器通过反序列化 InitializeComponent 中的代码来做到这一点。设计器支持的每种语言都有一个 CodeDomProvider,它负责提供一个解析器,该解析器解析 InitializeComponent 中的代码并创建它的 CodeDom 表示。然后,设计人员调用一组 CodeDomSerializer 将其反序列化为可以添加到设计时表单的实际控件(或更广泛地说,组件)。现在,我已经掩盖了该描述中的很多细节,但这里的重点是 Form1 的构造函数和 InitializeComponent 从未真正被调用过。相反,设计者解析 InitializeComponent 中的语句以确定要实例化哪些控件并将其添加到表单中。


以上是 Visual Studio 中的 Windows 窗体设计器如何加载窗体。如果您正在寻找的是一种创建没有默认构造函数并且仍然可以访问包含的组件/控件的表单实例的方法,那么我不知道有解决方案。我知道的唯一允许您绕过缺少默认构造函数的方法是FormatterServices.GetUninitializedObject,但要注意...

因为对象的新实例被初始化为零并且没有运行构造函数,所以该对象可能不代表该对象认为有效的状态。

我也有一个需要实例化编译表单的应用程序,但一直使用Activator.CreateInstance并要求其他开发人员至少包含一个私有默认构造函数,如果他们希望他们的表单可以在我的应用程序中访问。由于我们拥有整个代码库并且每个人都知道需求,所以这不是问题并且对我们来说效果很好。

于 2009-05-16T14:45:47.863 回答
0

作为史蒂夫回答的补充,如果您将新的 Windows 窗体添加到项目中,但使其抽象化,您仍然可以在设计器中打开它。但是,如果您添加另一个表单,并使其派生自第一个(抽象)表单,则在尝试在设计器中打开该表单时会出现错误。

于 2009-05-16T14:49:11.477 回答