Question Creating a parent control within a control

Pirahnaplant

Well-known member
Joined
Mar 29, 2009
Messages
75
Programming Experience
3-5
I'm trying to create a control with a parent control designer behavior, but unlike a regular parent control, I need a control inside of it to be the one that controls are put on. It needs to be similar to the tabcontrol, where controls can be placed on the individual tab pages, but not on other areas of the control, such as the tabs themselves. Does anyone know how to do this?

Here is what I mean:
parentcontrol.png
 
There's a basic example here: http://www.vbdotnetforums.com/component-development/25052-creating-control-panel.html
In addition override CanParent in control designer, where you return True when a control can be added. In example linked if I wanted only to allow controls to be added to the Panel I would check 'If TypeOf Me.Control Is Panel'. Me.Control in control designer refers to the control the designer is currently designing.
 
Thank you, it works great.

I have another question though. With this method, the user is allowed to make changes to the panel such as properties and resizing. Is it possible to disallow this?
 
Last edited:
You probable have to inherit the panel control, shadow Location/Size properties and apply Browsable attribute and other behaviours, and apply a separate designer where you override SelectionRules.
 
Here is a more extended example, a UserControl (RestrictArea) containing a GroupBox (Box), controls can only be added to the box container. Both classes has their own designer.

RestrictArea:
The user control exposes the Box as a property, DesignerSerializationVisibility (Content) attribute is added so that code is generated for adding controls to it.
Imports System.ComponentModel

<Designer(GetType(RestrictAreaDesigner))> _
Public Class RestrictArea '(inherits UserControl)

    <DesignerSerializationVisibility(DesignerSerializationVisibility.Content)> _
    Public ReadOnly Property Box() As Box
        Get
            Return Me.Box1
        End Get
    End Property
End Class

Box:
Box class hides a few properties, expand as needed and/or add custom behaviour. DesignerSerializationVisibility is not hidden for Location and Size since code for these need to be serialized, if not they would reset to default each rebuild. While properties can be hidden by overriding PreFilterProperties in control designer, this will only hide the property from designer, so they will still be available in code. Therefore it is best to Shadow the property as shown in Box class to hide properties that should not be available.
Notice the ToolboxItem attribute on Box class, I added that after adding a box to the user control from ToolBox, much more convenient to design the user control and adding the attribute hides it from ToolBox after that.
Imports System.ComponentModel

<Designer(GetType(BoxDesigner)), ToolboxItem(False)> _
Public Class Box
    Inherits GroupBox

    <EditorBrowsable(EditorBrowsableState.Never), Browsable(False)> _
    Public Shadows Property Location As Point
        Get
            Return MyBase.Location
        End Get
        Set(value As Point)
            MyBase.Location = value
        End Set
    End Property

    <EditorBrowsable(EditorBrowsableState.Never), Browsable(False)> _
    Public Shadows Property Size As Size
        Get
            Return MyBase.Size
        End Get
        Set(value As Size)
            MyBase.Size = value
        End Set
    End Property

    <EditorBrowsable(EditorBrowsableState.Never), Browsable(False), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)> _
    Public Shadows Property Dock As DockStyle
        Get
            Return MyBase.Dock
        End Get
        Set(value As DockStyle)
            MyBase.Dock = value
        End Set
    End Property

End Class


Here are their designers, requires reference to System.Design assembly.

RestrictAreaDesigner:
Inherits ParentControlDesigner because CanParent need to be used. CanParent returns False, no controls can be added directly to the user control. This has no effect when designing the user control itself, only when designing an instance of it on a form.
About the Initialize method. The code in previous example using Container.Add will make the added component standalone (ex "Box"), while using EnableDesignMode method adds the control as a child control (ex "RestrictArea.Box"). Latter makes sense here having a fixed sub-area within the user control. Designers for child controls added by EnableDesignMode is exposed by NumberOfInternalControlDesigners and InternalControlDesigner function overrides as shown. This difference can also be seen with TabControl/TabPage (separate pages) and SplitContainer/SplitterPanel (fixed child panels).
Imports System.Windows.Forms.Design
Imports System.ComponentModel.Design

Public Class RestrictAreaDesigner
    Inherits ParentControlDesigner

    Private boxdesigner As ScrollableControlDesigner

    Public Overrides Sub Initialize(ByVal component As System.ComponentModel.IComponent)
        MyBase.Initialize(component)
        Dim area As RestrictArea = DirectCast(component, RestrictArea)
        EnableDesignMode(area.Box, "Box")
        Dim host As IDesignerHost = DirectCast(GetService(GetType(IDesignerHost)), IDesignerHost)
        Me.boxdesigner = host.GetDesigner(area.Box)
    End Sub

    Public Overrides Function CanParent(control As System.Windows.Forms.Control) As Boolean
        Return False
    End Function

    Public Overrides Function NumberOfInternalControlDesigners() As Integer
        Return 1
    End Function

    Public Overrides Function InternalControlDesigner(internalControlIndex As Integer) As System.Windows.Forms.Design.ControlDesigner
        Return Me.boxdesigner
    End Function

End Class

BoxDesigner:
Inherits ScrollableControlDesigner, which is derived from ParentControlDesigner, add support for AutoScroll container.
CanParent need not overriding here, default allows all parenting.
CanBeParentedTo, similar to TabPage the Box should only be parented to RestrictArea user control.
SelectionRules, the box is locked in designer, can't be moved or resized.
Imports System.Windows.Forms.Design
Imports System.ComponentModel.Design

Public Class BoxDesigner
    Inherits ScrollableControlDesigner

    Public Overrides ReadOnly Property SelectionRules As System.Windows.Forms.Design.SelectionRules
        Get
            Return SelectionRules.Locked
        End Get
    End Property

    Public Overrides Function CanBeParentedTo(parentDesigner As System.ComponentModel.Design.IDesigner) As Boolean
        Return TypeOf parentDesigner.Component Is RestrictArea
    End Function

End Class

As always, study the documentation for the involved classes, also studying existing classes using .Net Reflector can be useful, for example the mentioned TabControl/TabPage and SplitContainer/SplitterPanel their designers.
 
Back
Top