2011-09-15 31 views
11

今天在工作中,我偶然發現了一個讓我瘋狂的問題。如何在窗體設計器中編輯可編輯的Collection <MyClass>類型的用戶控件屬性?

基本上我的目標是:

我有一個UserControl1,與類型Collection<Class1>的字段和相應的屬性Collection<Class1> Prop。就像這樣:

public class UserControl1 : UserControl 
{ 
    private Collection<Class1> field = null; 
    // later changed to: 
    //private Collection<Class1> field = new Collection<Class1>(); 
    [Category("Data")] 
    [DefaultValue(null)] 
    [Description("asdf")] 
    public Collection<Class1> prop 
    { 
     get { return field; } 
     set { field = value; } 
    } 
}
// later added: 
//[Serializable] 
public class Class1 
{ 
    private bool booltest; public bool Booltest { get...set...} 
    private int inttest; public int Inttest { get...set...} 
}

如果你已經知道我搞砸了:無需讀取休息。我將描述我到底做了什麼。

現在我將UserControl放到一個隨機表格中,並更改Prop屬性。出現一個通用的「集合編輯器」,就像用於列表視圖控件中的列和組的那樣。我可以按預期輸入數據。但是,當我點擊確定時,數據就消失了。

花了我一個多小時才發現我實際上必須實例化我的字段:private Collection<MyClass> field = new Collection<MyClass>();。非常好,只有設計師進入超級模式。級聯噩夢錯誤信息可以縮減爲:「您必須在Class1之前放置[Serializable]」。這樣做後,我可以再次將我的UserControl1放在窗體上。

但是,只有一次。當打開,我使用UserControl1編輯的東西后,窗體的設計,它給了我一個錯誤:

Object of type 'userctltest.Class1[]' cannot be converted to type 'userctltest.Class1[]'.

嘛。錯誤列表說:

Warning: ResX file Object of type 'userctltest.Class1[]' cannot be converted to type 'userctltest.Class1[]'. Line 134, position 5. cannot be parsed.

設計者試圖從RESX文件讀取屬性的數據。刪除resx文件「解決」只有一次。

表單現在可以再次顯示,與我UserControl1。收藏屬性可編輯,並且正在保存。它實際上工作。一旦。每當我改變一些東西然後嘗試再次打開窗體的設計器時,上述錯誤再次發生。我可以刪除resx文件,但這當然也會刪除我的數據。

,幫助我至今(一噸不那麼有用的搜索結果中)相關資源:

http://www.codeproject.com/Answers/190675/Usercontrol-with-custom-class-property#answer1
http://www.codeproject.com/KB/cs/propertyeditor.aspx
http://www.csharpfriends.com/Articles/getArticle.aspx?articleID=94
http://msdn.microsoft.com/en-us/library/system.runtime.serialization.iserializable.aspx

(我也嘗試推行了ISerializable和壓倒一切GetObjectData與

{ info.AddValue("testbool", testbool); info.AddValue("testint", testint); }

並沒有幫助(我也嘗試了屬性名稱,而不是字段名))

對不起,順便說一句寫這就像一個糟糕的恐怖小說。

回答

11

你想要的是CodeDom系列化的設計時間支持。你不需要SerializableAttributeISerializable,這些是用於二進制序列化。 由於您要序列化集合,因此必須告訴設計器將其序列化。這是通過DesignerSerializationVisibiliby屬性完成的--的值告訴設計者序列化屬性內容而不是屬性本身。該屬性的內容當然應該是CodeDom可序列化的,具有簡單屬性的簡單類是默認的。

所以,如果你改變你的UserControl1類是這樣的:

public class UserControl1 : UserControl 
{ 
    private Collection<Class1> field = new Collection<Class1>(); 

    [Category("Data")] 
    [Description("asdf")] 
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] 
    public Collection<Class1> prop 
    { 
     get { return field; } 
    } 
} 

...它應該做的伎倆。哦,集合屬性通常是不可寫的,雖然這不是強制性的。但是序列化程序期望集合屬性被初始化,這就是爲什麼你必須爲該字段添加初始化。 另一個說明,如果你不希望你的財產在財產編輯器中用粗體標記,你可以通過一個特殊的方法ShouldSerializePropertyName指定一個更復雜的「默認值」,它甚至可以是私人的。像這樣:

private bool ShouldSerializeprop() 
{ 
    return (field.Count > 0); 
} 

現在你的財產只有在它不是空的時候纔是大膽的。但是,我離題,這不是一個問題:)

+0

這似乎工作。儘管當我第一次嘗試它時,設計師再次饒有興致地發出了一聲噓噓的聲音(不是可序列化的等等)。經過一小時的擺弄(最終沒有改變任何東西)(我檢查了顛覆),它完美無缺地工作。這是有史以來最奇怪的事情:/ Thanks – dialer

+0

如果您的用戶控件與窗體位於同一個項目中,則必須在使用用戶控件之前構建項目。 Designer會查看已編譯的程序集,而不是您的代碼。 – Patko

2

完美爲例是這樣的:

public partial class SCon : UserControl 
    { 
     public SCon() 
     { 
      InitializeComponent(); 
      if (Persoanas == null) 
      { 
       Persoanas = new List<Persoana>(); 
      } 
     } 

     [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] 
     public List<Persoan> Persoanas { get; set; } 

    } 

    [Serializable] 
    public class Persoan 
    { 
     public int Id { get; set; } 
     public String Name { get; set; } 
    } 
0

只要改變Collection<>List<>

相關問題