2011-04-16 86 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付費(如果它事項)被寫入。