6

I wrote User Control (yay!). But I want it to behave as a container. But wait! I know about

[Designer("System.Windows.Forms.Design.ParentControlDesigner, System.Design", 
    typeof(IDesigner))]

Trick.

The problem is - I don't want all of my control to behave like container, but only one part. One - de facto - panel ;)

To give wider context: I wrote a control that has Grid, some common buttons, labels and functionalities. But it also has a part where the user is supposed to drop his custom buttons/controls whatever. Only in this particular part of the control, nowhere else.

Anyone had any idea?

Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
Thaven
  • 1,857
  • 3
  • 19
  • 35
  • 1
    I am not familiar with usercontrols, but cant you just put a panel on the region where you want the user to be able to drop controls on ? Maybe you also need to change the `modifier`property of that panel – GuidoG Jun 08 '18 at 11:07
  • @GuidoG - unfortunately, no :(. modifier works fine while inheriting, but as far as I tried, there's no way to make "editability" on a component from User Control this way. – Thaven Jun 08 '18 at 11:48
  • thats probably the reason again why i never use usercontrols but inherit direct from what i need or from Panel – GuidoG Jun 08 '18 at 11:50

1 Answers1

8

You should do the following :

  • For your user control, you need to create a new designer which enables the inner panel on design-time by calling EnableDesignMode method.
  • For the inner panel, you need to create a designer which disables moving, resizing and removes some properties from designer.
  • You should register the designers.

Example

You can read a blog post about this topic here and clone or download a working example:

enter image description here

Code

Here is the code for different elements of the solution.

Your user control

[Designer(typeof(MyUserControlDesigner))]
public partial class MyUserControl : UserControl
{
    public MyUserControl()
    {
        InitializeComponent();
        TypeDescriptor.AddAttributes(this.panel1,
            new DesignerAttribute(typeof(MyPanelDesigner)));
    }
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public Panel ContentsPanel
    {
        get { return panel1; }
    }
}

Designer for the inner panel

public class MyPanelDesigner : ParentControlDesigner
{
    public override SelectionRules SelectionRules
    {
        get
        {
            SelectionRules selectionRules = base.SelectionRules;
            selectionRules &= ~SelectionRules.AllSizeable;
            return selectionRules;
        }
    }
    protected override void PostFilterAttributes(IDictionary attributes)
    {
        base.PostFilterAttributes(attributes);
        attributes[typeof(DockingAttribute)] = 
            new DockingAttribute(DockingBehavior.Never);
    }
    protected override void PostFilterProperties(IDictionary properties)
    {
        base.PostFilterProperties(properties);
        var propertiesToRemove = new string[] {
            "Dock", "Anchor", "Size", "Location", "Width", "Height",
            "MinimumSize", "MaximumSize", "AutoSize", "AutoSizeMode",
            "Visible", "Enabled",
        };
        foreach (var item in propertiesToRemove)
        {
            if (properties.Contains(item))
                properties[item] = TypeDescriptor.CreateProperty(this.Component.GetType(),
                    (PropertyDescriptor)properties[item],
                    new BrowsableAttribute(false));
        }
    }
}

Designer for your user control

public class MyUserControlDesigner : ParentControlDesigner
{
    public override void Initialize(IComponent component)
    {
        base.Initialize(component);
        var contentsPanel = ((MyUserControl)this.Control).ContentsPanel;
        this.EnableDesignMode(contentsPanel, "ContentsPanel");
    }
    public override bool CanParent(Control control)
    {
        return false;
    }
    protected override void OnDragOver(DragEventArgs de)
    {
        de.Effect = DragDropEffects.None;
    }
    protected override IComponent[] CreateToolCore(ToolboxItem tool, int x,
        int y, int width, int height, bool hasLocation, bool hasSize)
    {
        return null;
    }
}
Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
  • Reza, I wanted this to work for me when I first discovered your post. tried to apply this example to a TableLayoutPanel. When I changed the type of the Contents Panel from Panel to TableLayoutPanel (TLP) and tested, I lost design-time features for the layout panel when I dragged the user control onto a design surface. For example, I saw the Columns property when I selected the ContentsPanel control, but when I changed it from 0 to, say, 2, the columns do not appear on the designer instance of the control. I also couldn't seem to access more advanced TLP properties (such as rows/cols metrics). – Jazimov Feb 01 '20 at 21:02
  • 1
    @Jazimov I think it will not work well for `TableLayouPanel` because of [some limitations](https://stackoverflow.com/a/49894861/3110834) of `TableLayoutPanel`. – Reza Aghaei Feb 01 '20 at 21:05
  • 1
    Ah, such is life. :) I still am happy with your Solution 2 for question https://stackoverflow.com/questions/59965679/keeping-adorner-glyphs-on-top-for-selected-control-in-winforms-designer/60018351?noredirect=1#comment106149441_60018351. I hope others can benefit from that approach. – Jazimov Feb 01 '20 at 21:07