今天上班时,我偶然发现了一个让我疯狂的问题。
基本上我的目标是:
我有一个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
属性。将出现一个通用的“集合编辑器”,类似于listview控件中的列和组。我可以按预期输入数据。但是,当我单击“确定”时,数据就会消失。
我花了一个多小时才弄清楚我实际上必须实例化我的字段:private Collection<MyClass> field = new Collection<MyClass>();
。非常好,只有设计师进入了超级模式。级联噩梦错误消息可以简化为:“您必须将[Serializable]
放在Class1
之前。”在这样做之后,我实际上可以再次将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文件中获取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); }
也没有帮助(我也试过了属性名而不是字段名))
很抱歉写这篇文章就像一部糟糕的恐怖小说。
答案 0 :(得分:13)
您想要的是CodeDom序列化的设计时支持。您不需要SerializableAttribute
或ISerializable
,这些用于二进制序列化。
由于您要序列化集合,因此必须告诉设计者将其序列化。这是通过DesignerSerializationVisibiliby属性完成的 - Content
的值告诉设计者序列化属性内容而不是属性本身。该属性的内容当然应该是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);
}
现在,您的属性只有在非空时才会变为粗体。但我离题了,这不是一个问题:)
答案 1 :(得分:3)
完美的例子就是:
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; }
}
答案 2 :(得分:0)
只需将Collection<>
更改为List<>