如何在表单设计器中使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序列化的设计时支持。 您不需要SerializableAttribute
或ISerializable
,它们用于二进制序列化。 由于您要序列化集合,因此必须告诉设计者将其序列化。 这是使用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<>