Custom Control Doesn't Update in Visual Studio Designer
Asked Answered
M

2

7

I'm creating a custom control that lays out radio buttons (No it doesn't have to be radio buttons. I'm just trying to learn how to do this so I can make some more complex stuff down the road that may contain multiple lists of controls) which are added through the Items property (similar to some other controls).

I can build the project, drag this onto a form from the component panel and add radio buttons via the Items property. Unfortunately this is not updated in designer unless you either:

  • Rebuild the project 2-3 times
  • Close and reopen the form in designer

At first I had the logic that puts these on the form contained in the constructor after Initialize but that wasn't working so I moved to to Form_Load.

What am I missing? The above options are just short term workarounds, not solutions.

RBLTest.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace WFCL_Library
{
    public partial class RBLTest : UserControl
    {
        private List<RadioButton> _items;

        private int leftSpacing = 100;
        private int topSpacing = 25;

        public RBLTest()
        {
            _items = new List<RadioButton>();
            InitializeComponent();
        }

        private void RadioButtonList_Load(object sender, EventArgs e)
        {
            int curLeftPos = 0;
            int curTopPos = 0;
            foreach (RadioButton rb in _items)
            {
                rb.Location = new Point(curLeftPos, curTopPos);
                rb.Size = new Size(85, 17);

                curLeftPos += leftSpacing;

                if (curLeftPos > this.Width)
                {
                    curLeftPos = 0;
                    curTopPos += topSpacing;
                }

                this.Controls.Add(rb);                
            }
        }

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

RBLTest.Designer.cs

namespace WFCL_Library
{
    partial class RBLTest
    {
        /// <summary> 
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary> 
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Component Designer generated code

        /// <summary> 
        /// Required method for Designer support - do not modify 
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.SuspendLayout();
            // 
            // RBLTest
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.Name = "RBLTest";
            this.Size = new System.Drawing.Size(407, 44);
            this.Load += new System.EventHandler(this.RadioButtonList_Load);
            this.ResumeLayout(false);

        }

        #endregion

    }
}
Mislay answered 13/9, 2012 at 19:42 Comment(0)
S
4

You should't use the Load event or the constructor, because when you add the control with the designer tool an instance of the UserControl is created and the Load event is fired. In your case when this happens _item is still empty. Another issue is that there are some problems serializing a list, so I'd use an array:

public partial class RBLTest : UserControl {
    private RadioButton[] _items;

    private int leftSpacing = 100;
    private int topSpacing = 25;

    public RBLTest( ) {
        InitializeComponent( );
    }

    [DesignerSerializationVisibility( DesignerSerializationVisibility.Content )]
    public RadioButton[] Items {
        get {
            return _items;
        }
        set {
            _items = value;

            int curLeftPos = 0;
            int curTopPos = 0;
            foreach ( RadioButton rb in _items ) {
                rb.Location = new Point( curLeftPos, curTopPos );
                rb.Size = new Size( 85, 17 );

                curLeftPos += leftSpacing;

                if ( curLeftPos > this.Width ) {
                    curLeftPos = 0;
                    curTopPos += topSpacing;
                }

                this.Controls.Add( rb );
            }
        }
    }
}

The result in the Form Designer:

enter image description here

Scallop answered 13/9, 2012 at 20:55 Comment(3)
Ohhhhhhhhhhhh I just want to hug you right now, I spent so long toying with this with no luck finding anything on this subject with my poor google searches. Do you happen to have a reference to an article discussing the issues with serializing generic lists in the designer?Mislay
@Mislay You don't need another collection, you already have one in the Controls collection which is where your child controls have to live anyhow.Boydboyden
No sincerly I've never used a list and I don't know if it's possible, but if you need a list you can do in the property setter: List<RadioButton> list = _items.ToList();.Scallop
B
0

The reason is that you are adding controls to the ControlsCollection only in the Load event. Here is a tutorial on creating container controls in WinForms that I googled: http://www.codeproject.com/Articles/9238/WinForms-Custom-Container-Control

Boydboyden answered 13/9, 2012 at 20:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.