【问题标题】:How does the Winforms Designer instantiate my form?Winforms Designer 如何实例化我的表单?
【发布时间】:2010-10-26 17:32:21
【问题描述】:

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

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

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

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

TIA。

注意:我发现这个 related question 没有令人满意的答案

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

【问题讨论】:

  • 您可能会发现自定义现有 Windows 窗体设计元素而不是重新发明它们会更好。他们处理各种你不会想到的场景,直到你的用户抱怨他们缺乏。
  • 约翰,这正是我的观点。你认为我在哪里重新发明了任何东西?

标签: winforms visual-studio-2008 designer windows-forms-designer


【解决方案1】:

找到这个here

当你打开一个新的 Windows VS 中的应用程序项目,您会看到一个 设计中名为 Form1 的空表单 看法。现在,你还没有建立 项目还没有,那么设计师怎么样 能够创建 Form1 的实例 并展示它?好吧,设计师不是 真正实例化 Form1。它 正在创建基础实例 Form1 的类,即, System.Windows.Forms.Form。带一个 面向对象的基础知识 编程,你会发现这个 直觉上是有道理的。当你在 设计 Form1,您从 基类,Form,并自定义它。 这正是设计师想要的 帮你做。

现在假设您添加了一堆 控件到窗体并关闭 设计师。当您重新打开 设计师,控件还在 那里。但是,基类 Form 没有这些控件,所以 如果设计师没有运行 Form1的构造函数,它是如何显示的 控制?设计师这样做 通过反序列化代码 初始化组件。每种语言 设计师支持有一个 负责的 CodeDomProvider 用于提供解析器 InitializeComponent 中的代码和 创建一个 CodeDom 表示 它。然后设计者调用一组 CodeDomSerializers 反序列化这个 进入实际控制(或更广泛地说, 组件),它可以添加到 设计时表格。现在,我已经擦亮了 里面有很多细节 描述,但这里的重点是 Form1 的构造函数和 InitializeComponent 从来都不是真的 调用。相反,设计者解析 InitializeComponent 中的语句 弄清楚要控制什么 实例化并添加到表单中。


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

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

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

【讨论】:

  • 史蒂夫,非常有趣的链接。谢谢!它几乎证实了我想象的一般机制,但我不知道 CodeDom。将立即深入研究;-)
  • CodeDoms 在尝试加载 compiled 自定义表单类型时似乎让我陷入了死胡同:-(
  • "没有运行构造函数" -- 在相关说明中,这不适用于 UserControls,如果我在 UserControl 的构造函数中放置一个无限循环并尝试拖动它变成一种形式,它锁定了视觉工作室。在链接的 msdn 博客页面上的 cmets 中还提到了其他一些例外情况。
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 2010-10-22
    • 1970-01-01
    • 1970-01-01
    • 2016-10-27
    • 1970-01-01
    • 1970-01-01
    • 2016-09-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多