2011-04-16 87 views
9

此之前已经多次发生过没有初始化,但我从来没有费心去搞清楚为什么,现在我累了:自定义用户控件中自动生成的代码

举例来说,我得到从RichTextBox中类或面板,我重建我的项目,将类添加到VS设计器工具箱,然后我拖动自定义用户控件到窗体。一切工作正常,我可以运行我的项目...

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

换句话说,下面一行是从说,Form1.Designer.cs删除:

this.customRichTextBox1=new CustomRichTextBox(); 

没有其他线从代码隐藏去除,所以自定义控件的属性仍设置,尽管变量保持未初始化。

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

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

class CustomRichTextBox:RichTextBox{} 

这太令人讨厌了。我究竟做错了什么?


作为@Cody请求,这里是重现问题的步骤。我使用的是VS2010,但自2005年以来我就遇到了这个问题,我想。

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

第2步:添加下面主窗体类以下类:(碰巧,这是导致我这个问题,本次的控制。 )

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步。要纠正问题,请进入代码隐藏并初始化变量,但下次重新构建,初始化线将消失。

+0

几天前发布了类似的问题,但他们的问题和您的问题都没有提供足够的代码来实际重现问题。我花了很多时间开发自定义控件库并使用VS Designer,我从未见过这种情况。我并不否认这发生在你身上,但如果我自己无法再现问题,我无法帮助你找到解决方案。设计师有时候很古怪,但并不完全不可救药。 – 2011-04-16 06:10:04

+0

@Cody:感谢您的评论。我测试并添加了重现问题的步骤。我希望你能重现它。你是对的,设计师是一个非常强大的工具,它很少给我带来麻烦。我会说这是唯一一个我必须与之战斗的实例......我相信这个问题与我通过自己输入课程来创建控制的方式有关。 – 2011-04-16 06:36:23

回答

11

感谢大家谁回答我的问题,谁发布评论,帮助我诊断和解决问题。

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

非常感谢你:) – 2011-11-06 17:47:33

+1

这个解决方案也适合我。干杯! – pennyrave 2013-05-28 14:03:05

0

您的内部版本设置为“调试”还是“版本”? 我想这是发布,因为我认为编译器优化代码并删除设计器生成的行。

+0

感谢Sonosar,但它设置为调试。编译器不应删除该行,因为该控件在其属性被设置时仍然被引用。换句话说,即使将其初始化的行被删除,分配其属性的行仍留下以使用未初始化的对象。对于编译器来说,删除初始化行而没有其他行是没有意义的。无论如何,据我所知,编译器不会从实际的源文件中删除东西。它只从最终的可执行文件中删除东西。 – 2011-04-16 06:51:39

0

你有没有尝试把控制代码放在它自己的文件中?过去,当设计师的代码不是他在文件中的第一堂课时,我甚至在使用表单设计器时遇到了问题。

+0

你可能是对的!我会尽快尝试。我从来没有想到这一点,但它是有道理的,因为设计师确实需要它自己的设计器生成的控件成为文件中的第一个。 – 2011-04-16 15:47:25

+0

同样的问题。给这个类自己的文件没有帮助。不管怎么说,多谢拉。 :( – 2011-04-16 15:59:18

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 OS VS2012付费(如果它事项)被写入。