用于在 WinForms 设计器中生成 AddRange() 的自定义 TypeConverter 不起作用

A custom TypeConverter for generates AddRange() in WinForms designer not working

来自问题:

以下 TypeConverter 不生成 AddRange()。虽然我看到一些控件以相同的代码方式生成它。

Form1.designer.cs

        // userControl11
        // 
        this.userControl11.BackColor = System.Drawing.Color.Red;
        this.userControl11.Fruits.Add(new WindowsFormsApp2.Fruit(false, null));
        this.userControl11.Fruits.Add(new WindowsFormsApp2.Fruit(false, null));
        this.userControl11.Fruits.Add(new WindowsFormsApp2.Fruit(false, null));
        this.userControl11.Fruits.Add(new WindowsFormsApp2.Fruit(false, null));
        this.userControl11.Fruits.Add(new WindowsFormsApp2.Fruit(false, null));
        this.userControl11.Fruits.Add(new WindowsFormsApp2.Fruit(false, null));
        this.userControl11.Fruits.Add(new WindowsFormsApp2.Fruit(false, null));
        this.userControl11.Location = new System.Drawing.Point(278, 224);
        this.userControl11.Name = "userControl11";

应该是

this.userControl1.Fruits.AddRange(new Fruite[]{new Fruit(X, Y), new Fruit(X, Y), etc})

虽然我看到标准控件做同样的事情,但它生成得很好:

    // listBox1
    // 
    this.listBox1.FormattingEnabled = true;
    this.listBox1.Items.AddRange(new object[] {   // WORKS in standard controls...
    "123",
    "123",
    "123"});

我的代码:

 [TypeConverter(typeof(FruitConverter))]
    public class Fruit
    {
        public Fruit() { }
        public Fruit(bool edible, string name) : this()
        {
            Edible = edible;
            Name = name;
        }
        public bool Edible { get; set; }
        public string Name { get; set; }
    }

    public class FruitConverter : ExpandableObjectConverter
    {
        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
        {
            if (destinationType == typeof(InstanceDescriptor)) return true;
            return base.CanConvertTo(context, destinationType);
        }
        public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
        {
            if (destinationType == typeof(InstanceDescriptor) && (value is Fruit pi))
            {
                ConstructorInfo ctor = typeof(Fruit).GetConstructor(new Type[] { typeof(bool), typeof(string) });
                object[] pars = new object[] { pi.Edible, pi.Name };
                return new InstanceDescriptor(ctor, pars);
            }
            return base.ConvertTo(context, culture, value, destinationType);
        }
    }

在用户控件中测试

public partial class UserControl1 : UserControl
{
    public UserControl1()
    {
        InitializeComponent();
    }


    private Collection<Fruit> fruits = new Collection<Fruit>();
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public Collection<Fruit> Fruits => fruits;

}

我现在该怎么办?

真的太难了。但这里的文章解释了一些: https://www.codeproject.com/Articles/5372/How-to-Edit-and-Persist-Collections-with-Collectio

Third, the collection class must implement one or both of the following methods: Add and AddRange. Although IList interface has an Add member and CollectionBase implements IList, you still have to implement an Add method for your collection, given that CollectionBase declares an explicit member implementation of the IList’s Add member. The designer serializes the collection according to what method you have implemented. If you have implemented both, the AddRange is preferred.

当使用 Add 方法序列化时,它为每个项目使用一个新行。

this.tc.SimpleItems.Add(new Test.Items.SimpleItem_FullTc(-1, "Item1"));
this.tc.SimpleItems.Add(new Test.Items.SimpleItem_FullTc(-1, "Item2"));`

当设计人员使用 AddRange 方法时,所有项目都添加到一行中。

this.tc.SimpleItems.AddRange
  (new Test.Items.SimpleItem[]{new Test.Items.SimpleItem_FullTc(-1, "Item1"),
new Test.Items.SimpleItem_FullTc(-1, "Item2")});

所以你必须实现一个 class 继承自 Collection<T>CollectionBase 然后添加 AddRange() 方法。