自动生成的代码中未自定义自定义用户控件

时间:2011-04-16 05:56:47

标签: c# visual-studio user-controls custom-controls designer

之前已经发生了很多次,但我从来没有费心去弄清楚原因,现在我已经厌倦了:

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

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

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

this.customRichTextBox1=new CustomRichTextBox();

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

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

我相信当我通过设计器构建自定义UserControl时不会发生这种情况(但我并不完全确定)。只有当我手动定义类似下面的内容时才会发生这种情况:

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.要解决问题,请进入代码隐藏并初始化变量,但下次重建时,初始化行将消失。

4 个答案:

答案 0 :(得分:14)

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

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

答案 1 :(得分:0)

您的构建设置为Debug还是Release? 我认为它是发行版,因为我认为编译器会优化代码并删除设计器生成的行。

答案 2 :(得分:0)

您是否尝试将控制代码放在自己的文件中?我甚至在使用表单设计器时遇到了问题,因为设计器代码不是文件中的第一类。

答案 3 :(得分:0)

我有一个类似的问题,这个帖子帮我解决了。我有一个扩展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 });

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

通过反复试验和帖子:How to tell if .NET code is being run by Visual Studio designer提出了一个解决方案:

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

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编写的(如果重要的话)。