如何在表单设计器中创建Collection <myclass>类型的User控件属性?</myclass>

时间:2011-09-15 20:21:48

标签: c# .net visual-studio-2010 properties designer

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

基本上我的目标是:

我有一个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); }

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

很抱歉写这篇文章就像一部糟糕的恐怖小说。

3 个答案:

答案 0 :(得分:13)

您想要的是CodeDom序列化的设计时支持。您不需要SerializableAttributeISerializable,这些用于二进制序列化。 由于您要序列化集合,因此必须告诉设计者将其序列化。这是通过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<>

即可