Search code examples
c#winformsuser-controlswindows-forms-designerdesigner

Container UserControl - Handle and Modify Added Controls


I'm trying to create a custom container as UserControl.

My Goal: I want to be able to drag controls inside the designer and handle incoming controls inside the code of my usercontrol.

Example: I place my container somewhere and then add a button. In this momemt I want my usercontrol to automatically adjust the width and position of this button. Thats the point where Im stuck.

My code:

[Designer("System.Windows.Forms.Design.ParentControlDesigner, System.Design", typeof(IDesigner))]
public partial class ContactList : UserControl
{
    public ContactList()
    {
        InitializeComponent();
    }        

    private void ContactList_ControlAdded(object sender, ControlEventArgs e)
    {
        e.Control.Width = 200;   // Nothing happens
        e.Control.Height = 100;  // Nothing happens

        MessageBox.Show("Test"); // Firing when adding a control
    }
}

enter image description here

enter image description here

The MessageBox is working well. The set width and height is ignored.
The question is just "why?".


EDIT

I've just noticed, when placing the button and recompiling with F6 the button gets resized to 200x100. Why isnt this working when placing?

I mean... the FlowLayoutPanel handles added controls right when you place it. Thats the exact behaviour im looking for.

enter image description here


Solution

  • Using OnControlAdded

    To fix your code, when you drop a control on container and you want to set some properties in OnControlAdded you should set properties using BeginInvoke, this way the size of control will change but the size handles don't update. Then to update the designer, you should notify the designer about changing size of the control, using IComponentChangeService.OnComponentChanged.

    Following code executes only when you add a control to the container. After that, it respects to the size which you set for the control using size grab handles. It's suitable for initialization at design-time.

    protected override void OnControlAdded(ControlEventArgs e)
    {
        base.OnControlAdded(e);
        if (this.IsHandleCreated)
        {
            base.BeginInvoke(new Action(() =>
            {
                e.Control.Size = new Size(100, 100);
                var svc = this.GetService(typeof(IComponentChangeService)) 
                              as IComponentChangeService;
                if (svc != null)
                    svc.OnComponentChanged(e.Control, 
                       TypeDescriptor.GetProperties(e.Control)["Size"], null, null);
            }));
        }
    }