自定义用户控件未在自动生成的代码中初始化

发布于 2024-11-01 17:29:39 字数 1508 浏览 2 评论 0原文

这种情况以前发生过很多次,但我从来没有费心去弄清楚为什么,现在我厌倦了:

例如,我从RichTextBox或Panel派生一个类,我重建我的项目以将类添加到VS设计器工具箱,然后我拖动并将自定义用户控件拖放到窗体中。一切正常,我可以运行我的项目...

当我通过设计器编辑表单或自定义用户控件的属性时,问题就出现了。有时,设计器从其代码隐藏中删除初始化行,从而导致设计器和可执行文件出现异常,因为控件仍未初始化。

换句话说,从 Form1.Designer.cs 中删除了以下行:

this.customRichTextBox1=new CustomRichTextBox();

代码隐藏中没有删除其他行,因此自定义控件的属性仍然被设置,尽管变量保持未初始化状态。

我的解决方案一直是在设计器代码隐藏中手动初始化我的用户控件,但设计器最终再次将其删除。

我相信当我通过设计器构建自定义用户控件时不会发生这种情况(但我不完全确定这一点)。仅当我手动定义如下内容时才会发生这种情况:

class CustomRichTextBox:RichTextBox{}

这太烦人了。我做错了什么?


正如@Cody 所要求的,以下是重现问题的步骤。我正在使用 VS2010,但我认为自 2005 年以来我就遇到了这个问题。

步骤 1. 创建新的 Windows 窗体应用程序,任何框架

步骤 2. 在主 Form 类下面添加以下类:(恰好这是导致我这次出现此问题的控件。)

class CustomRichTextBox : RichTextBox
{
    Timer tt = new Timer();

    internal CustomRichTextBox()
    {
        tt.Tick += new EventHandler(tt_Tick);
        tt.Interval = 200;
    }


    protected override void OnTextChanged(EventArgs e)
    {
        tt.Stop();
        tt.Start();
    }

    void tt_Tick(object sender, EventArgs e)
    {
        System.Diagnostics.Trace.WriteLine("Hello world!");
    }
}

步骤 3. 按 F6 重建。

步骤 4. 通过从工具箱中拖放,将 CustomRichTextBox 控件添加到表单中。

步骤 5. 如果您愿意,可以按 F5 来测试应用程序,但它应该可以工作。关闭正在运行的应用程序。

步骤 6. 按 F6 进行重建,此时,设计器应该崩溃并显示以下消息:“变量‘customRichTextBox1’未声明或从未分配。” (在一种情况下,整个 VS 完全崩溃,但错误通常包含在设计器内。)

步骤 7. 要纠正问题,请进入代码隐藏并初始化变量,但下次重建时,初始化行将会消失。

This has happened many times before, but I never bothered to figure out why, and now I am tired of it:

For instance, I derive a class from RichTextBox or Panel, I rebuild my project to have the class added to the VS designer toolbox, and then I drag & drop the custom user control to a Form. Everything works fine, and I can run my project...

The problem comes when I edit properties of the Form or the custom user control through the designer. Sometimes, the designer removes the initialization line from its code-behind, causing an exception in the designer and the executable because the control remains uninitialized.

In other words, the following line is removed from say, Form1.Designer.cs:

this.customRichTextBox1=new CustomRichTextBox();

No other line is removed from the code-behind, so the attributes of the custom control are still set, although the variable stays uninitialized.

My solution has always been to manually initialize my user control in the designer code-behind, but the designer eventually removes it again.

I believe that this does not happen when I build a Custom UserControl through the designer (but I am not completely sure of this). It only happens when I define something like the following manually:

class CustomRichTextBox:RichTextBox{}

This is so annoying. What am I doing wrong?


As @Cody requested, here are the steps to reproduce the problem. I am using VS2010, but I've had this problem since 2005, I think.

Step 1. Create new Windows Forms Application, any Framework

Step 2. Add the following class below your main Form class: (It just happens that this is the control that is causing me this problem this time.)

class CustomRichTextBox : RichTextBox
{
    Timer tt = new Timer();

    internal CustomRichTextBox()
    {
        tt.Tick += new EventHandler(tt_Tick);
        tt.Interval = 200;
    }


    protected override void OnTextChanged(EventArgs e)
    {
        tt.Stop();
        tt.Start();
    }

    void tt_Tick(object sender, EventArgs e)
    {
        System.Diagnostics.Trace.WriteLine("Hello world!");
    }
}

Step 3. Press F6 to rebuild.

Step 4. Add the CustomRichTextBox control to your Form by dragging and dropping from the Toolbox.

Step 5. If you wish, you may press F5 to test the application, but it should work. Close the running application.

Step 6. Press F6 to rebuild, and at this point, the designer should crash with the following message: "The variable 'customRichTextBox1' is either undeclared or was never assigned." (In one case, the whole VS completely crashed, but the error is usually contained within the designer.)

Step 7. To correct the issue, go into the code-behind and initialize the variable, but next time you rebuild, the initialization line will be gone.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

一曲琵琶半遮面シ 2024-11-08 17:29:39

感谢所有尝试回答我的问题以及发表评论帮助我诊断和解决问题的人。

将“internal”关键字与控件的构造函数一起使用时会出现此问题。将其更改为“公共”可以解决问题。出现此行为的原因可能是设计者自己的类无法看到构造函数,因为它们不在我的类的命名空间内,除非将其标记为公共。这一切都是有道理的,从现在开始我将使用 public 关键字。

该类不需要位于其自己的单独文件中,也不需要像其他答案所建议的那样成为文件中第一个声明的类。

下面的类运行良好,因为构造函数的关键字已更改为 public。

class CustomRichTextBox : RichTextBox
{
    Timer tt = new Timer();

    public CustomRichTextBox()
    {
        tt.Tick += new EventHandler(tt_Tick);
        tt.Interval = 200;
    }


    protected override void OnTextChanged(EventArgs e)
    {
        tt.Stop();
        tt.Start();
    }

    void tt_Tick(object sender, EventArgs e)
    {
        System.Diagnostics.Trace.WriteLine("Hello world!");
    }
}

Thanks to everyone who tried answering my question and who posted comments that helped me diagnose and solve the problem.

The problem occurs when using an "internal" keyword with the control's constructor. Changing it to "public" fixes the problem. The reason for this behavior might be that the Designer's own classes cannot see the constructor because they are not within the namespace of my class unless it is marked public. This all makes sense, and I will use the public keyword from now on.

The class does not need to be in its own individual file or be the first declared class in the file as other answers suggested.

The following class works well because the constructor's keyword was changed to public.

class CustomRichTextBox : RichTextBox
{
    Timer tt = new Timer();

    public CustomRichTextBox()
    {
        tt.Tick += new EventHandler(tt_Tick);
        tt.Interval = 200;
    }


    protected override void OnTextChanged(EventArgs e)
    {
        tt.Stop();
        tt.Start();
    }

    void tt_Tick(object sender, EventArgs e)
    {
        System.Diagnostics.Trace.WriteLine("Hello world!");
    }
}
萝莉病 2024-11-08 17:29:39

您的构建设置为“调试”还是“发布”?
我认为它已发布,因为我认为编译器优化了代码并删除了设计器生成的行。

Is your build set to Debug or it is Release?
I suppose that it is release as I think compiler optimizes the code and remove designer generated line.

乞讨 2024-11-08 17:29:39

您是否尝试过将控制代码放在自己的文件中?过去,当设计器代码不是文件中的第一类时,即使是表单设计器,我也遇到过问题。

Have you tried putting the control code in its own file? I've had problems even with the form designer in the past when the designer code was not int he first class in the file.

困倦 2024-11-08 17:29:39

我遇到了类似的问题,这篇文章帮助我解决了。我有一个扩展 ComboBox 的 CustomControl,该类包含一个内部私有类 YearItem。我试图仅突出显示理解问题和解决方案所需的代码。

public class YearsCbo : ComboBox //Inherits ComboBox
{
    public YearsCbo() { 
        fill();
    }
    private void fill() { // <<<=== THIS METHOD ADDED ITEMS TO THE COMBOBOX
        for(int idx = 0; idx < 25; idx++) {
            this.Items.Add(new YearItem());
        }
    }
    // Other code not shown
    private class YearItem {} // <<<=== The VS designer can't access this class and yet 
        // it generated code to try to do so.  That code then fails to compile.
        // The compiler error rightfully says it is unable to access 
        // the private class YearItem
}

我可以将该控件 YearsCbo 拖放到表单上,它可以正常工作,但在我返回并编辑表单后,VS 设计器生成的代码无法编译。有问题的代码是这样的:

Dim YearItem1 As my.ns.YearsCbo.YearItem = New my.ns.YearsCbo.YearItem()
Dim YearItem2 As my.ns.YearsCbo.YearItem = New my.ns.YearsCbo.YearItem()
// This was repeated 25 times because in my constructor I created 25 of these
Me.YearsCbo1.Items.AddRange(New Object() {YearItem1, 2, 3, ..., YearItem25 });

请注意,设计器生成的代码试图访问私有类。它不需要这样做,但出于某种原因它这样做了。

通过反复试验,以及这篇文章: 如何判断.NET代码是否正在由Visual Studio设计器运行提出了一个解决方案:

我添加了一个属性来判断我是否正在设计器中运行。

public bool HostedDesignMode
{
    get
    {
        if (System.ComponentModel.LicenseManager.UsageMode == System.ComponentModel.LicenseUsageMode.Designtime)
            return true;
        else
            return false;
    }
}

我还更改了构造函数,以便它不会调用 fill(),因此当设计器运行时,ComboBox 中没有项目,因此设计器感觉不需要手动创建这些项目。

“固定”代码如下所示:

public class YearsCbo : ComboBox //Inherits ComboBox
{
    public YearsCbo() { 
        if ( ! HostedDesignMode ) {
            fill();
        }
    }
    private class YearItem {} // <<<=== Now the VS Designer does not try to access this
}

该代码是在 Win7x64 操作系统上使用 VS2012 Premium 编写的(以防万一)。

I had a similar problem that this posted helped me solve. I have a CustomControl that extends ComboBox, that class contained an internal private class YearItem. I've tried to highlight only the code needed to understand the problem and the solution.

public class YearsCbo : ComboBox //Inherits ComboBox
{
    public YearsCbo() { 
        fill();
    }
    private void fill() { // <<<=== THIS METHOD ADDED ITEMS TO THE COMBOBOX
        for(int idx = 0; idx < 25; idx++) {
            this.Items.Add(new YearItem());
        }
    }
    // Other code not shown
    private class YearItem {} // <<<=== The VS designer can't access this class and yet 
        // it generated code to try to do so.  That code then fails to compile.
        // The compiler error rightfully says it is unable to access 
        // the private class YearItem
}

I could drag/drop that control YearsCbo onto a form and it worked correctly, but after I returned and edited the form the VS designer generated code that would not compile. The offending code something like this:

Dim YearItem1 As my.ns.YearsCbo.YearItem = New my.ns.YearsCbo.YearItem()
Dim YearItem2 As my.ns.YearsCbo.YearItem = New my.ns.YearsCbo.YearItem()
// This was repeated 25 times because in my constructor I created 25 of these
Me.YearsCbo1.Items.AddRange(New Object() {YearItem1, 2, 3, ..., YearItem25 });

Notice that the designer generated code which tried to access the private class. It didn't need to do that but for some reason it did.

Through trial and error, and this post: How to tell if .NET code is being run by Visual Studio designer came up with a solution:

I added a property to tell if I am running in the designer.

public bool HostedDesignMode
{
    get
    {
        if (System.ComponentModel.LicenseManager.UsageMode == System.ComponentModel.LicenseUsageMode.Designtime)
            return true;
        else
            return false;
    }
}

I also changed the constructor so that it doesn't call fill() so when the designer runs, there are no items in the ComboBox so the designer doesn't feel the need to manually create those items.

The "fixed" code is shown below:

public class YearsCbo : ComboBox //Inherits ComboBox
{
    public YearsCbo() { 
        if ( ! HostedDesignMode ) {
            fill();
        }
    }
    private class YearItem {} // <<<=== Now the VS Designer does not try to access this
}

This code was written using VS2012 Premium on Win7x64 OS (in case it matters).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文