无法在C#编写窗体时查看设计师

8

我正在跟随this关于winforms的教程,目前为止该教程是在不使用工具箱进行窗体编码。我相信它很快会更深入地介绍工具箱。

按照教程,我已经在以下两个代码片段中创建了一个部分类:

第一个文件:

using System;
using System.Windows.Forms;

public class Numeric : System.Windows.Forms.TextBox
{
    public Numeric()
    {
    }
}

public partial class Exercise
{
    private Numeric txtbox;
    System.ComponentModel.Container components;
}

第二个文件:

using System;
using System.Windows.Forms;

public partial class Exercise : Form
{
    private void InitializeComponent()
    {
        txtbox = new Numeric();
        Controls.Add(txtbox);
    }

    public Exercise()
    {
        InitializeComponent();
    }
}

public class program
{
    public static int Main()
    {
        Application.Run(new Exercise());
        return 0;
    }
}

当我使用F5运行代码时,一切看起来都很好:表单弹出并显示文本框。
但是由于某种原因,当我右键单击第二个文件并选择“查看设计器”时,会出现错误,提示“变量'txtbox'未声明或从未赋值”。我可以选择“忽略并继续”,然后就会得到一个没有文本框的表单。
为什么会发生这种情况?我知道有些人认为我应该使用工具箱,这可能是最明智的做法,但我仍然希望了解为什么会发生这种情况。

你必须声明txtbox的类型。它在哪里?你不能期望设计师展示InitializeComponent()中发生的任何事情。 - Yogee
你正在使用一些第三方控件吗? 如果是的话,那么它导致了你面临的这个问题。 - Lali
@Yogee 我在第一个文件中声明了txtbox的类型,我认为由于这个类是partial的,它应该可以很好地找到类型。 - HowDoICSharply
@Lali 好的,但我只使用标准控件。 - HowDoICSharply
2个回答

15

Windows Forms 设计器是如何工作的?

当你在 Windows Forms 设计器中打开一个 Form 时,设计器会查找文件中的第一个类。如果文件包含一个 Designer.cs,其中包含了其他部分类的其他部分,它也会将其包含进来并试图对这些文件内容进行反序列化。在反序列化和加载你的窗体的设计时,它会创建一个你的表单基类的实例,并在这些文件中查找组件声明和 InitializeComponents 方法。如果找到它们,则使用反序列化代码创建组件并设置其属性,并将这些组件添加到创建的基类实例中。

一些实用信息:

  • 你的 Form 构造函数中的代码不会在设计时执行,但你的表单基类构造函数会在设计时执行。
  • InitializeComponent 中的代码不会在设计时执行,但这些代码将被反序列化并用于创建表单的设计。
  • 设计器无法显示具有抽象基类的表单。(解决方案
  • 设计器无法显示泛型类的表单。例如,它无法显示 MyForm:SomeForm<SomeClass>,但它可以显示 SomeForm<T>:Form。(解决方案
  • 如果你为表单定义了一个新属性,则属性不会显示在属性窗口中。属性窗口显示的是基类的属性,但其值是你的表单的值。
  • 当一个文件包含2个类时,如果表单不是第一个类,那么设计器将无法加载,并会提示说该表单应该是第一个类以便在设计器中显示。
  • 上述规则也适用于用户控件。

示例

看看下面的代码,其中有一些严重的问题:

  • 类的构造函数与类名不同
  • 语句 int i="x";
  • 这是一个 C# 类,但没有分号
  • InitializeComponent 方法没有在构造函数中调用

但有趣的是,即使有这些错误,你也可以在设计器中看到表单!

只需创建一个文件并将以下代码放入文件中,保存文件并关闭它。然后在不尝试构建解决方案的情况下,在设计器中打开表单即可。下面是代码:

using System
using System.Windows.Forms
namespace SampleApplication
{
    public class MyForm:Form
    {
        public NotMyForm()
        {
        }
        public void InitializeComponent()
        {
            int i="x";
            textBox1 = new TextBox()
            textBox1.Text = "Hi"
            this.Controls.Add(textBox1)
        }
        private TextBox textBox1
    }
}

这是设计师的屏幕截图:

输入图像描述

更多信息

要查找更多信息,请查看此链接:

您的问题的解决方案

作为解决方案,您只需将private Numeric txtbox;移动并将其放入Exercise类的第二个文件中即可。


2
非常感谢!这对我有点意义。我以下的理解是正确的吗?当我要求VS显示表单时,它不会编译任何东西;它只会解析和反序列化(似乎意味着将代码转换为字节),因此即使我的类是部分类,它也不会看到类的另一半?类的另一半是我初始化“txtbox”的地方,但它看不到。如果我把所有东西放在同一个(非部分)类中,我就不应该在设计器上遇到问题了。 - HowDoICSharply
是的,您对幕后发生的事情有很好的理解。设计师通过使用 CodeDom 序列化器解析和转换您编写的代码为控件实例,并将它们添加到基类的实例中并显示在设计表面上。 - Reza Aghaei

1

控件的声明应该放在Designer.cs文件中,这样Visual Studio就可以编译这个单元并显示它。

当你启动应用程序时,编译器会考虑到你的部分类的所有部分,然后找到txtBox的声明。

尝试将仅包含表单类及其图形声明的单个文件保留下来。这个单个文件应该有一个InitializeComponent方法,在InitializeComponent()中初始化UI组件的构造函数和字段声明。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接