我已经构建了此自定义控件,其中包含项目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));
}
}
答案 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中。您可能需要实现ShouldSerializexxx
和Resetxxx
。对于这类事情,这些通常是一个好主意。
℃。为什么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
:
(Click for larger image)
事先,它显示简单的TypeName(或者它可能是静态的,如NewHeaderItem
),然后一旦设置了属性,就会显示Name。
This CodeProject article可能看似无关,但有一些与Collections,TypeConverters,Designer Serialization等相关的好的启动内容。该代码在VB中,但概念应该足够清楚。免责声明:我写了这篇文章。
1 请参阅MSDN Guidelines for Collections。
2 基于那里的什么。