2011-09-15 27 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<>

相关问题