Visual Studio 设计器不为 `Windows.Forms.Control` 的 `List<T>` 成员生成代码
Visual Studio designer does not generate code for `List<T>` members of `Windows.Forms.Control`
下面的class(一个WindowsForms控件)是一种列表控件,
ListControlItem
不继承任何 Windows 控件 class.
public class ListControl : Control
{
private List<ListControlItem> items;
public ListControl()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose(disposing);
}
void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.items = new List<ListControlItem>();
}
public List<ListControlItem> Items
{
get { return items; }
set { items = value; }
}
}
问题是,在设计时,Visual Studio 尝试将列表内容序列化到表单的资源文件中,而不是像 ListView
和 ListViewItem
.
Visual Studio 为 ListControl
设计生成的代码:
this.listControl1.Items = ((System.Collections.Generic.List<ListControlItem>)(resources.GetObject("listControl1.Items")));
对于ListView
:
System.Windows.Forms.ListViewItem listViewItem1 = new System.Windows.Forms.ListViewItem("");
System.Windows.Forms.ListViewItem listViewItem2 = new System.Windows.Forms.ListViewItem("");
System.Windows.Forms.ListViewItem listViewItem3 = new System.Windows.Forms.ListViewItem("");
System.Windows.Forms.ListViewItem listViewItem4 = new System.Windows.Forms.ListViewItem("");
System.Windows.Forms.ListViewItem listViewItem5 = new System.Windows.Forms.ListViewItem("");
System.Windows.Forms.ListViewItem listViewItem6 = new System.Windows.Forms.ListViewItem("");
this.listView1.Items.AddRange(new System.Windows.Forms.ListViewItem[] {
listViewItem1,
listViewItem2,
listViewItem3,
listViewItem4,
listViewItem5,
listViewItem6});
我试图搜索 ListView
和 ListViewItem
来解决问题,
ListView
的 "own list class" 名为 ListViewItemCollection
,它实现了接口 IList, ICollection, IEnumerable
,但 List<T>
实现了相同的接口。
我需要为它实现自定义序列化吗?也许这只会序列化到资源文件。我找不到太多文档,因为它没有继承任何 Windows Forms Control 基础 classes.
更新
将属性 [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
放入 List<T>
属性 为每个 List<T>
项目提供一个资源。
this.listControl1.Items.Add(((ListControlItem)(resources.GetObject("listControl1.Items"))));
this.listControl1.Items.Add(((ListControlItem)(resources.GetObject("listControl1.Items1"))));
this.listControl1.Items.Add(((ListControlItem)(resources.GetObject("listControl1.Items2"))));
this.listControl1.Items.Add(((ListControlItem)(resources.GetObject("listControl1.Items3"))));
this.listControl1.Items.Add(((ListControlItem)(resources.GetObject("listControl1.Items4"))));
this.listControl1.Items.Add(((ListControlItem)(resources.GetObject("listControl1.Items5"))));
这就像为 ListControlItem
实现自定义序列化可以提供帮助。
有必要为 class 实施 TypeConverter
。这个 TypeConverter
所做的只是 return 为 class.
创建构造函数描述符
此外,使用参数 [TypeConverter(typeof(typeConverter))]
.
指定 class 的 TypeConverter
根据 MSDN How to: Implement a Type Converter,在这种情况下,更具体地说是 为 属性 初始化在 运行 时间 生成代码的类型转换器。
The .NET Framework provides the capability to generate dynamic
property initialization code at design time that will initialize a
property at run time.
Developers can build a type converter that produces constructor-based
initialization code. These type converters can generate constructor
code dynamically using values set at design time in order to configure
properties of a type at run time. The type converter implements the
logic to configure the type and values of a constructor for the
property.
Visual Studio 设计器的结果代码
this.listControl1.Items.Add(new ListControlItem());
this.listControl1.Items.Add(new ListControlItem());
this.listControl1.Items.Add(new ListControlItem());
this.listControl1.Items.Add(new ListControlItem());
this.listControl1.Items.Add(new ListControlItem());
this.listControl1.Items.Add(new ListControlItem());
TypeConverter
return 只是一个无参数构造函数,但可以在 TypeConverter
代码中更改。
关于CodeDomSerializer
If you need to produce code besides a constructor to initialize a
property, it is possible to dynamically generate code by implementing
a custom CodeDomSerializer and applying a DesignerSerializerAttribute
that associates your CodeDomSerializer for a type with the type. This
approach is typically used only for scenarios in which dynamically
controlled or customized code generation for component initialization
is important. For more information on this approach, see the
documentation for CodeDomSerializer.
也就是说,使用answer方法,需要在构造函数参数上传递属性值。如果还不够(比如不在构造函数上设置属性),那么可能需要像@Octopoid 所说的那样使用 CodeDomSerializer
。
下面的class(一个WindowsForms控件)是一种列表控件,
ListControlItem
不继承任何 Windows 控件 class.
public class ListControl : Control
{
private List<ListControlItem> items;
public ListControl()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose(disposing);
}
void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.items = new List<ListControlItem>();
}
public List<ListControlItem> Items
{
get { return items; }
set { items = value; }
}
}
问题是,在设计时,Visual Studio 尝试将列表内容序列化到表单的资源文件中,而不是像 ListView
和 ListViewItem
.
Visual Studio 为 ListControl
设计生成的代码:
this.listControl1.Items = ((System.Collections.Generic.List<ListControlItem>)(resources.GetObject("listControl1.Items")));
对于ListView
:
System.Windows.Forms.ListViewItem listViewItem1 = new System.Windows.Forms.ListViewItem("");
System.Windows.Forms.ListViewItem listViewItem2 = new System.Windows.Forms.ListViewItem("");
System.Windows.Forms.ListViewItem listViewItem3 = new System.Windows.Forms.ListViewItem("");
System.Windows.Forms.ListViewItem listViewItem4 = new System.Windows.Forms.ListViewItem("");
System.Windows.Forms.ListViewItem listViewItem5 = new System.Windows.Forms.ListViewItem("");
System.Windows.Forms.ListViewItem listViewItem6 = new System.Windows.Forms.ListViewItem("");
this.listView1.Items.AddRange(new System.Windows.Forms.ListViewItem[] {
listViewItem1,
listViewItem2,
listViewItem3,
listViewItem4,
listViewItem5,
listViewItem6});
我试图搜索 ListView
和 ListViewItem
来解决问题,
ListView
的 "own list class" 名为 ListViewItemCollection
,它实现了接口 IList, ICollection, IEnumerable
,但 List<T>
实现了相同的接口。
我需要为它实现自定义序列化吗?也许这只会序列化到资源文件。我找不到太多文档,因为它没有继承任何 Windows Forms Control 基础 classes.
更新
将属性 [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
放入 List<T>
属性 为每个 List<T>
项目提供一个资源。
this.listControl1.Items.Add(((ListControlItem)(resources.GetObject("listControl1.Items"))));
this.listControl1.Items.Add(((ListControlItem)(resources.GetObject("listControl1.Items1"))));
this.listControl1.Items.Add(((ListControlItem)(resources.GetObject("listControl1.Items2"))));
this.listControl1.Items.Add(((ListControlItem)(resources.GetObject("listControl1.Items3"))));
this.listControl1.Items.Add(((ListControlItem)(resources.GetObject("listControl1.Items4"))));
this.listControl1.Items.Add(((ListControlItem)(resources.GetObject("listControl1.Items5"))));
这就像为 ListControlItem
实现自定义序列化可以提供帮助。
有必要为 class 实施 TypeConverter
。这个 TypeConverter
所做的只是 return 为 class.
此外,使用参数 [TypeConverter(typeof(typeConverter))]
.
TypeConverter
根据 MSDN How to: Implement a Type Converter,在这种情况下,更具体地说是 为 属性 初始化在 运行 时间 生成代码的类型转换器。
The .NET Framework provides the capability to generate dynamic property initialization code at design time that will initialize a property at run time.
Developers can build a type converter that produces constructor-based initialization code. These type converters can generate constructor code dynamically using values set at design time in order to configure properties of a type at run time. The type converter implements the logic to configure the type and values of a constructor for the property.
Visual Studio 设计器的结果代码
this.listControl1.Items.Add(new ListControlItem());
this.listControl1.Items.Add(new ListControlItem());
this.listControl1.Items.Add(new ListControlItem());
this.listControl1.Items.Add(new ListControlItem());
this.listControl1.Items.Add(new ListControlItem());
this.listControl1.Items.Add(new ListControlItem());
TypeConverter
return 只是一个无参数构造函数,但可以在 TypeConverter
代码中更改。
关于CodeDomSerializer
If you need to produce code besides a constructor to initialize a property, it is possible to dynamically generate code by implementing a custom CodeDomSerializer and applying a DesignerSerializerAttribute that associates your CodeDomSerializer for a type with the type. This approach is typically used only for scenarios in which dynamically controlled or customized code generation for component initialization is important. For more information on this approach, see the documentation for CodeDomSerializer.
也就是说,使用answer方法,需要在构造函数参数上传递属性值。如果还不够(比如不在构造函数上设置属性),那么可能需要像@Octopoid 所说的那样使用 CodeDomSerializer
。