Winforms Designer如何实例化我的表单?

时间:2021-03-27 15:53:08

I'm developing my own WinForms designer. It must be able to load existing custom form types. One of the issues I hit is forms without a default ctor: My code currently instantiates the form before it can load it into the designer, which requires a default ctor.

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

OTOH, VS2008 is able to load such forms. I believe it doesn't actually instantiate my form (as noted in this question): Even default ctors are not executed. And it doesn't truly execute InitializeComponent(). I just added a messagebox in that function and it doesn't show.

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

It looks like it dynamically mimic the custom form type and executes only parts of the code in InitializeComponent which it thinks is relevant.

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

Does anyone know where I can find more information regarding how the VS designer works.

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

TIA.

Note: I found this related question without satisfying answers

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

EDIT: Additional info: Steve points me to CodeDom, which is very insteresting. My problem though is that the types I need to load into my designer are already compiled instead of being available as source code. I can't find any way to apply CodeDom deserialization to compiled code.

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

2 个解决方案

#1


Found this here:

在这里找到:

When you open a new Windows Application project in VS, you see an empty form called Form1 in design view. Now, you haven't built the project yet, so how is the designer able to create an instance of Form1 and show it? Well, the designer is not really instantiating Form1 at all. It is creating an instance of the base class of Form1, i.e., System.Windows.Forms.Form. With a basic knowledge of object oriented programming, you will find that this intuitively makes sense. When you are designing Form1, you start with the base class, Form, and customize it. This is exactly what the designer helps you to do.

在VS中打开新的Windows应用程序项目时,您会在设计视图中看到名为Form1的空表单。现在,您尚未构建项目,那么设计人员如何能够创建Form1的实例并显示它?好吧,设计师根本没有真正实例化Form1。它正在创建Form1基类的实例,即System.Windows.Forms.Form。有了面向对象编程的基本知识,你会发现这在直觉上是有意义的。在设计Form1时,首先要使用基类Form,然后对其进行自定义。这正是设计师帮助您做的事情。

Now let's say you added a bunch of controls to the Form and closed the designer. When you reopen the designer, the controls are still there. However, the base class Form doesn't have these controls on it, so if the designer isn't running the constructor of Form1, how did it show the controls? The designer does this by deserializing the code in InitializeComponent. Each language that the designer supports has a CodeDomProvider that is responsible for providing a parser that parses the code in InitializeComponent and creates a CodeDom representation of it. The designer then invokes a set of CodeDomSerializers to deserialize this into actual Controls (or more broadly, Components) that it can add to the design time Form. Now, I have glossed over a lot of details in that description, but the point here is that Form1's constructor and InitializeComponent are never really invoked. Instead, the designer parses the statements in InitializeComponent to figure out what controls to instantiate and add to the form.

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


The above is how Windows Forms designer in Visual Studio loads a form. If what you are looking for is a way to create an instance of a form that has no default constructor and still have access to the contained components/controls, I'm not aware of a solution. The only method I'm aware of that allows you to bypass the lack of a default constructor is FormatterServices.GetUninitializedObject, but beware ...

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

Because the new instance of the object is initialized to zero and no constructors are run, the object might not represent a state that is regarded as valid by that object.

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

I too have an app that requires instantiating compiled forms but have always used Activator.CreateInstance and required other developers to include, at the very least, a private default constructor if they want their form accessible in my app. Since we own the entire codebase and everyone is aware of the requirement, this isn't a problem and works out well for us.

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

#2


As an addition to Steve's answer, if you add a new Windows Form to a project, but make it abstract, you can still open it in the designer. However, if you add another form, and have it derive from the first (abstract) form, you get an error when attempting to open the form in the designer.

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

#1


Found this here:

在这里找到:

When you open a new Windows Application project in VS, you see an empty form called Form1 in design view. Now, you haven't built the project yet, so how is the designer able to create an instance of Form1 and show it? Well, the designer is not really instantiating Form1 at all. It is creating an instance of the base class of Form1, i.e., System.Windows.Forms.Form. With a basic knowledge of object oriented programming, you will find that this intuitively makes sense. When you are designing Form1, you start with the base class, Form, and customize it. This is exactly what the designer helps you to do.

在VS中打开新的Windows应用程序项目时,您会在设计视图中看到名为Form1的空表单。现在,您尚未构建项目,那么设计人员如何能够创建Form1的实例并显示它?好吧,设计师根本没有真正实例化Form1。它正在创建Form1基类的实例,即System.Windows.Forms.Form。有了面向对象编程的基本知识,你会发现这在直觉上是有意义的。在设计Form1时,首先要使用基类Form,然后对其进行自定义。这正是设计师帮助您做的事情。

Now let's say you added a bunch of controls to the Form and closed the designer. When you reopen the designer, the controls are still there. However, the base class Form doesn't have these controls on it, so if the designer isn't running the constructor of Form1, how did it show the controls? The designer does this by deserializing the code in InitializeComponent. Each language that the designer supports has a CodeDomProvider that is responsible for providing a parser that parses the code in InitializeComponent and creates a CodeDom representation of it. The designer then invokes a set of CodeDomSerializers to deserialize this into actual Controls (or more broadly, Components) that it can add to the design time Form. Now, I have glossed over a lot of details in that description, but the point here is that Form1's constructor and InitializeComponent are never really invoked. Instead, the designer parses the statements in InitializeComponent to figure out what controls to instantiate and add to the form.

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


The above is how Windows Forms designer in Visual Studio loads a form. If what you are looking for is a way to create an instance of a form that has no default constructor and still have access to the contained components/controls, I'm not aware of a solution. The only method I'm aware of that allows you to bypass the lack of a default constructor is FormatterServices.GetUninitializedObject, but beware ...

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

Because the new instance of the object is initialized to zero and no constructors are run, the object might not represent a state that is regarded as valid by that object.

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

I too have an app that requires instantiating compiled forms but have always used Activator.CreateInstance and required other developers to include, at the very least, a private default constructor if they want their form accessible in my app. Since we own the entire codebase and everyone is aware of the requirement, this isn't a problem and works out well for us.

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

#2


As an addition to Steve's answer, if you add a new Windows Form to a project, but make it abstract, you can still open it in the designer. However, if you add another form, and have it derive from the first (abstract) form, you get an error when attempting to open the form in the designer.

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