如何在表单设计器中使Collection 类型的用户控件属性可编辑?

今天上class时,我偶然发现了一个让我疯狂的问题。

基本上我的目标是:

我有一个UserControl1 ,其字段类型为Collection ,相应的属性Collection Prop 。 像这样:

 public class UserControl1 : UserControl { private Collection field = null; // later changed to: //private Collection field = new Collection(); [Category("Data")] [DefaultValue(null)] [Description("asdf")] public Collection 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属性。 将出现一个通用的“集合编辑器”,类似于listview控件中的列和组。 我可以按预期输入数据。 但是,当我单击“确定”时,数据消失了。

花了我一个多小时来弄清楚我实际上必须实例化我的字段: private Collection field = new Collection(); 。 非常好,只有设计师进入了超级模式。 级联噩梦错误消息可以简化为:“你必须在Class1之前放置[Serializable] 。” 在这之后,我实际上可以将我的UserControl1再次放在Form上。

但那只能工作一次。 在打开我在编辑内容时使用UserControl1的Form的设计器时,它给出了一个错误:

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文件中获取Property的数据。 删除resx文件“解决”一次。

现在可以使用UserControl1再次显示表单。 Collection属性可编辑的,并且正在保存。 它确实有效。 一旦。 每当我更改某些内容然后再次尝试打开Form的设计器时,会再次出现上述错误。 我可以删除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); }

也没有帮助(我也尝试了属性名称而不是字段名称))

对不起写这个像坏恐怖小说顺便说一句。

您想要的是CodeDom序列化的设计时支持。 您不需要SerializableAttributeISerializable ,它们用于二进制序列化。 由于您要序列化集合,因此必须告诉设计者将其序列化。 这是使用DesignerSerializationVisibiliby属性完成的 – Content值告诉设计者序列化属性内容而不是属性本身。 该属性的内容当然应该是CodeDom可序列化的,默认情况下具有简单属性的简单类。

因此,如果您更改UserControl1类,如下所示:

 public class UserControl1 : UserControl { private Collection field = new Collection(); [Category("Data")] [Description("asdf")] [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] public Collection prop { get { return field; } } } 

……它应该做的伎俩。 哦,集合属性通常是不可写的,虽然这不是强制性的。 但是序列化程序期望初始化集合属性,这就是为什么必须为字段添加初始化的原因。 另请注意,如果您不希望属性在属性编辑器中标记为粗体,则可以通过特殊方法ShouldSerializePropertyName指定更复杂的“默认值”,它甚至可以是私有的。 像这样:

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

现在,您的属性只有在非空时才会变为粗体。 但我离题了,这不是一个问题:)

完美的例子是这样的:

 public partial class SCon : UserControl { public SCon() { InitializeComponent(); if (Persoanas == null) { Persoanas = new List(); } } [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] public List Persoanas { get; set; } } [Serializable] public class Persoan { public int Id { get; set; } public String Name { get; set; } } 

只需将Collection<>更改为List<>