2

The following class (a Windows Forms Control) is a type of list control, and the ListControlItem don't inherit any Windows Control 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; }
    }
}

The problem is, at Design Time, Visual Studio tries to serialize the list content to the resource file of the Form, instead of creating the code for instantiating each item and then adding to the control like with ListView and ListViewItem.

Visual Studio design generated code for ListControl:

        this.listControl1.Items = ((System.Collections.Generic.List<ListControlItem>)(resources.GetObject("listControl1.Items")));

For 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});

I tried to search the ListView and ListViewItem to solve the problem, ListView has its "own list class" named ListViewItemCollection that implements the interfaces IList, ICollection, IEnumerable, but List<T> implements the same interfaces.

Does I need to implement a custom serialization for it? Maybe this would just serialize to the resources file. I can't find much documentation as it don't inherit any Windows Forms Control base classes.

UPDATE

Putting the attribute [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] in the List<T> property gives one resource for each List<T> item.

        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"))));

Thats like implementing a custom serialization for ListControlItem can help.

5
  • What are you hoping to achieve? There may be another way of approaching the issue. Commented Jan 27, 2015 at 23:51
  • The same of ListView. Making the Visual Studio designer generate code for each ListControlItem instead of putting on the resource file. Commented Jan 27, 2015 at 23:52
  • AFAIK you'd need to use the CodeDOM for this. This should allow you to define how code is generated into the partial designer class. Commented Jan 27, 2015 at 23:56
  • Specifically I think you'd want to use CodeDomSerializer, as you suspect in the last paragraph. Commented Jan 27, 2015 at 23:57
  • This is near a duplicate question, but with Int as the type for the List<T>. @Octopoid yes, the MSDN documents the CodeDomSerializer like you said, but only for custom types or if there is a need to serialize the property in a custom way. Otherwise it should serialize using the reflection api, so I don't think its needed. Maybe implementing a class for the List<T> can help. Commented Jan 28, 2015 at 1:23

1 Answer 1

1

It's necessary to implement a TypeConverter for the class. What this TypeConverter do is just returning a constructor descriptor for the class.

Also, specify the TypeConverter of the class using the parameter [TypeConverter(typeof(typeConverter))].

According to MSDN How to: Implement a Type Converter in this case more specifically on the Type Converters That Generate Code for Property Initialization at Run Time.

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.

The resulting code of the Visual Studio designer

        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());

The TypeConverter return just a no parameter constructor, but that can be changed in the TypeConverter code.

About the 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.

That is, with the answer method, the properties values need to be passed on the constructor parameters. If is not sufficient (like setting properties not on the constructor), then it may be necessary to use CodeDomSerializer like @Octopoid said.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.