1

I'm designing a custom Wizard control via a UserControl. I am using a sub-control in it called WizardPageControl which is derived from TabControl to host the wizard pages and need this editable in the designed view of the final Wizard User Control. I have achieved this via the code below:

[Designer(typeof(WizardDesigner))]
public partial class Wizard : BaseUserControl
{
    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public WizardPageControl WizardPageControlArea
    {
        get { return wizardPageControl; }
    }

    public Wizard()
    {
        InitializeComponent();
    }
}


internal class WizardDesigner : ParentControlDesigner
{

    public override void Initialize(System.ComponentModel.IComponent component)
    {
        base.Initialize(component);
        var uc = (Wizard)component;
        EnableDesignMode(uc.WizardPageControlArea, "WizardPageControlArea");            
    }
}

If I construct a simple Wizard UserControl with A Label Docked to the Top, another Label docked to the bottom and a WizardPageControl named wizardPageControl set to Dock Fill, I get this when I build and place the control on a form:

enter image description here

All good. Except when I close and re-open the form, I get this (the move handle and outlined box is wizardPageControl):

enter image description here

Basically, wizardPageControl Dock-Fill has expanded to fill the whole form, not between the top and bottom label docks. So, simple: put it in a panel, right? No dice. As soon as I put it in any kind of container, VS crashes when trying to add the Wizard UserControl to any form. I'm guessing that this is because wizardPageControl (and its corresponding public Property WizardPageControlArea) is no longer a direct child control of the form, rather a child control of another container.

I've read through the MS documentation for EnableDesignMode and also INestedContainer but as ever found it about as useful as an umbrella in a typhoon.

Any help would be gratefully received.

stuartd
  • 70,509
  • 14
  • 132
  • 163
stigzler
  • 793
  • 2
  • 12
  • 29
  • 1
    [User control containing child control, design mode edit child control](https://stackoverflow.com/a/39925620/7444103) -- [UserControl with header and content - Allow dropping controls in content panel and Prevent dropping controls in header at design time](https://stackoverflow.com/a/50772584/7444103) – Jimi Apr 29 '23 at 20:36
  • Thanks yet again Jimi! These were helpful in polishing my use of custom designers, but sadly didn't solve the problem. The real issue lies in accurately getting the editable control to sit between the header and footer which is still eluding me. The second link was closest - he just sets the panel to Dock.Fill. When I do that with mine, it fills the whole usercontrol space behind the header and footer. As in the OP - nesting the wizardPageControl inside a panel might be the best bet - but getting crashes. Coming up to 3 days on this one now! grrrr.. – stigzler Apr 30 '23 at 11:14

1 Answers1

1

So I never solved this via nesting the editable control in a panel and docking it, but did approaching it via a different method. I position the control manually in the User Control OnLoad event and handle UC resizing via anchor properties on the editable control. In my example, I position it just below the top header and up to the top of the bottom footer, and set the anchor to left, top, right and bottom (that way it stretches with the control).

However, you also need to prevent the user from dragging controls onto the non-editable areas of the UC and also have to stop them resizing or moving the editable control. This is achieved via the code below:

[Designer(typeof(WizardDesigner))]
public partial class Wizard : BaseUserControl
{
    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public WizardPageControl WizardPageControlArea
    {
        get { return wizardPageControl; }
    }

    public Wizard()
    {
        InitializeComponent();
    }
    
    private void Wizard_Load(object sender, EventArgs e)
    {
        wizardPageControl.Location = new Point(0, TopPN.Height);
        wizardPageControl.Size = new Size(this.Width, this.Height - TopPN.Height - BottomPN.Height);
    }   
}

internal class WizardDesigner : ParentControlDesigner
{

    public override void Initialize(System.ComponentModel.IComponent component)
    {
        base.Initialize(component);
        var uc = (Wizard)component;
        EnableDesignMode(uc.WizardPageControlArea, "WizardPageControlArea");            
    }
    
    // prevents dropping of controls onto non-Design-mode enabled areas
    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;
    }   
}

[Designer(typeof(Designers.WizardPageControlDesigner))]
public class WizardPageControl: UIElements.TabControl
{
    public WizardPageControl()
    {
    }
}

internal class WizardPageControlDesigner : ParentControlDesigner
{
    // Prevents user from resizing or moving the editable control
    public override SelectionRules SelectionRules
    {
        get
        {
            SelectionRules selectionRules = base.SelectionRules;
            selectionRules &= ~SelectionRules.AllSizeable;
            selectionRules &= ~SelectionRules.Moveable;
            return selectionRules;
        }
    }
    
    // Hides other properties from user which may chnage the positoning of the control
    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","DrawMode","HideBorders","HideTabs"
            };
        foreach (var item in propertiesToRemove)
        {
            if (properties.Contains(item))
                properties[item] = TypeDescriptor.CreateProperty(this.Component.GetType(),
                    (PropertyDescriptor)properties[item],
                    new BrowsableAttribute(false));
        }
    }
}

Hope it saves someone the 2 days of my life that I lost to this!

stigzler
  • 793
  • 2
  • 12
  • 29