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

C# 自定义用户控件未在自动生成的代码中初始化,c#,visual-studio,user-controls,custom-controls,designer,C#,Visual Studio,User Controls,Custom Controls,Designer,这种情况以前发生过很多次,但我从未费心去弄清楚原因,现在我已经厌倦了: 例如,我从RichTextBox或Panel派生了一个类,我重建了我的项目,将该类添加到VS designer工具箱中,然后将自定义用户控件拖放到表单中。一切正常,我可以运行我的项目 当我通过设计器编辑窗体或自定义用户控件的属性时,就会出现问题。有时,设计器会从其代码中删除初始化行,从而导致设计器和可执行文件中出现异常,因为控件仍处于未初始化状态 换句话说,从Form1.Designer.cs中删除以下行: this.cus

这种情况以前发生过很多次,但我从未费心去弄清楚原因,现在我已经厌倦了:

例如,我从RichTextBox或Panel派生了一个类,我重建了我的项目,将该类添加到VS designer工具箱中,然后将自定义用户控件拖放到表单中。一切正常,我可以运行我的项目

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

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

this.customRichTextBox1=new CustomRichTextBox();
没有从代码隐藏中删除其他行,因此尽管变量保持未初始化状态,自定义控件的属性仍然设置

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

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

class CustomRichTextBox:RichTextBox{}
这太烦人了。我做错了什么


按照@Cody的要求,以下是重现问题的步骤。我使用的是VS2010,但我想我从2005年起就遇到了这个问题

第一步。创建新的Windows窗体应用程序、任何框架

第二步。在主窗体类下面添加以下类:(碰巧这是导致我这次出现此问题的控件。)

第三步。按F6键重建

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

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

第六步。按F6重新生成,此时,设计器应崩溃并显示以下消息:“变量‘customRichTextBox1’未声明或从未分配。”(在一种情况下,整个VS完全崩溃,但错误通常包含在设计器中。)


第七步。要更正此问题,请进入代码隐藏并初始化变量,但下次重新生成时,初始化行将消失。

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

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

感谢所有尝试回答我问题的人,他们发表了帮助我诊断和解决问题的评论

在控件的构造函数中使用“internal”关键字时会出现问题。将其更改为“public”可以解决此问题。这种行为的原因可能是设计器自己的类无法看到构造函数,因为它们不在我的类的命名空间内,除非它标记为public。这一切都是有道理的,从现在起我将使用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!");
    }
}

我有一个类似的问题,这个帖子帮助我解决了。我有一个扩展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
}
请注意,设计器生成了试图访问私有类的代码。它不需要这样做,但出于某种原因,它这样做了

经过反复试验,这篇文章:提出了一个解决方案:

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

public bool HostedDesignMode
{
    get
    {
        if (System.ComponentModel.LicenseManager.UsageMode == System.ComponentModel.LicenseUsageMode.Designtime)
            return true;
        else
            return false;
    }
}
我还更改了构造函数,这样它就不会调用fill(),这样当设计器运行时,组合框中就没有项了,所以设计器就不需要手动创建这些项

“固定”代码如下所示:

public class YearsCbo : ComboBox //Inherits ComboBox
{
    public YearsCbo() { 
        if ( ! HostedDesignMode ) {
            fill();
        }
    }
    private class YearItem {} // <<<=== Now the VS Designer does not try to access this
}
public class YearsCbo:ComboBox//继承ComboBox
{
公历年
如果(!HostedDesignMode){
填充();
}
}

私有类项{}//几天前发布了一个类似的问题,但他们的问题和你的问题都没有提供足够的代码来实际重现这个问题。我花了很多时间开发自定义控件库并与VS Designer合作,我从未见过这种情况发生。我不否认这种情况发生在你身上,但这是不可能的如果我自己不能重现问题,我可以帮你找到解决方案。设计师有时很古怪,但也不是完全无法解决的。@Cody:谢谢你的评论。我测试并添加了重现问题的步骤。我希望你能重现问题。你是对的,设计师是一个非常强大的工具,它很少给我带来麻烦。我想唉,这是唯一一个我必须与之抗争的实例…我相信,问题与我自己键入类来创建控件的方式有关。谢谢Sonosar,但它被设置为调试。编译器不应该删除该行,因为在设置其属性时控件仍然被引用。换句话说,即使尽管要初始化它的行被删除了,但分配其属性的行被留下来使用未初始化的对象。编译器删除初始化行而不删除其他行没有任何意义。无论如何,据我所知,编译器不会从实际的源文件中删除内容。它只从源文件中删除内容最终的可执行文件。你可能是对的!我会尽快尝试。我从未想过这一点,但它会让我感到惊讶
public bool HostedDesignMode
{
    get
    {
        if (System.ComponentModel.LicenseManager.UsageMode == System.ComponentModel.LicenseUsageMode.Designtime)
            return true;
        else
            return false;
    }
}
public class YearsCbo : ComboBox //Inherits ComboBox
{
    public YearsCbo() { 
        if ( ! HostedDesignMode ) {
            fill();
        }
    }
    private class YearItem {} // <<<=== Now the VS Designer does not try to access this
}