Collection类在构建时会丢失其项目

时间:2014-12-13 14:07:55

标签: c# winforms serialization custom-controls bindinglist

我已经构建了此自定义控件,其中包含项目class HeaderItem : Component, INotifyPropertyChanged。这些项目为BindingList<HeaderItem>

的列表

我最近一直在使用自定义控件遇到此问题,每次使用表单设计器构建项目时,控件都会丢失所有项目,但它们会保留在form.designer.cs文件中。

这是最重要的代码:

[DefaultEvent("SelectedIndexChanged"), DefaultProperty("Items")]
class Header : Control
{

    [field: NonSerialized]
    private BindingList<HeaderItem> _items = new BindingList<HeaderItem>();

    public Header()
    {
        _items.ListChanged += (sender, args) => 
        {
            if (SelectedIndex > Items.Count) SelectedIndex = Items.Count - 1;
            Invalidate();
        };
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public BindingList<HeaderItem> Items
    {
        get { return _items; }
    }

    [field: NonSerialized]
    public event EventHandler SelectedIndexChanged;

    protected virtual void OnSelectedIndexChanged()
    {
        EventHandler handler = SelectedIndexChanged;
        if (handler != null) handler(this, EventArgs.Empty);
    }

}

[DesignTimeVisible(false)]
class HeaderItem : Component, INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

2 个答案:

答案 0 :(得分:1)

尝试更改代码,如下所示:

    [DefaultEvent( "SelectedIndexChanged" ), DefaultProperty( "Items" )]
    class Header : Control
    {
        ...

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public BindingList<HeaderItem> Items
        {
            get { return _items; }
            set { _items = value; }
        }

       ...
}

答案 1 :(得分:1)

第一个问题是,当您使用.Hidden设置时,您告诉VS不要将其序列化。 Content表示该属性是一个对象,因此需要序列化内容:

[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public BindingList<HeaderItem> Items
{
    get { return _items; }
}

原始代码在省略setter 1 时是正确的。您可能不希望更改或重置内容 - 通过将List对象作为属性而不是集合类 1 ,您已经承担了一些责任。 VS序列化程序不会使用或不需要setter(任何Collection Editor也不会),使用Add / AddRange方法添加项目:

this.header1 = new WindowsFormsApplication1.Header();
this.headerItem1 = new WindowsFormsApplication1.HeaderItem();
this.headerItem2 = new WindowsFormsApplication1.HeaderItem();
...
this.header1.Items.Add(this.headerItem4);
this.header1.Items.Add(this.headerItem5);

其他问题和问题

很难确定,因为这里发布的课程明显简化了。例如,HeaderItem可能包含propertyName属性以保存正在观看的内容。但是稍微调整它以使其编译,这些问题出现了:

一个。如上所述,List属性类型可能很危险。

B中。您可能需要实现ShouldSerializexxxResetxxx。对于这类事情,这些通常是一个好主意。

℃。为什么HeaderItem继承自Component?

它似乎不需要是一个组件 2 。我怀疑你在某处读到这是一个简单的方法让VS / Net创建一个唯一的名称并为你序列化而无需编写TypeConverter。这很大程度上是正确的,但是如果您删除了Header控件/对象,则服务员HeaderItems可能会在表单设计器中保持孤立状态:

' Note that there is no Header control/object to add these to
this.label1 = new System.Windows.Forms.Label();
this.headerItem1 = new WindowsFormsApplication1.HeaderItem();
this.headerItem2 = new WindowsFormsApplication1.HeaderItem();
this.SuspendLayout();

通常,用户会从表单托盘中删除组件,但您的组件会被隐藏。与Components不同,当删除控件时,集合类对象将从设计器中删除。因此,除非您确实需要某些组件功能,否则请考虑更改它。

使用简单属性和无参数ctor,您可能不需要TypeConverter,也许某些属性。这个近乎克隆有三个字符串属性,不依赖于Component
enter image description here

Click for larger image
事先,它显示简单的TypeName(或者它可能是静态的,如NewHeaderItem),然后一旦设置了属性,就会显示Name。

This CodeProject article可能看似无关,但有一些与Collections,TypeConverters,Designer Serialization等相关的好的启动内容。该代码在VB中,但概念应该足够清楚。免责声明:我写了这篇文章。

1 请参阅MSDN Guidelines for Collections
2 基于那里的什么。