Search code examples
c#winformstabcontrolwindows-forms-designerdesigner

Controls added to TabPage of the TabControl of my UserControl disappear after rebuild


I have a UserControl which contains a TabControl. I enabled the designer of the TabControl and its TabPages so the user can add/remove/modify tab pages and add controls to tab pages.

When I add my UserControl to the Form and add controls on tab pages it's OK and controls can be added/removed/changed properly until I build the project or save changes and close and reopen the form.

When I build the project, every changes that I'd made in tab pages and each controls which I added to tab pages are removed. The controls exists on designer.cs but they doesn't show on tab pages.

Why do the controls I added to tab pages of the TabControl of my UserControl disappear after rebuild?

My user control source code:

Note: tbBody is a TabControl

[Designer(typeof(MainDesigner))]
public partial class MZTabControl : UserControl
{
    private bool isdesign = false;
    private bool allowtbodyresize = false;
    public MZTabControl()
    {
        InitializeComponent();
    }
    [Category("MZ TabControl"),
    DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public TabControl TabControlArea
    {
        get
        {
            return tbBody;
        }
    }
}

My designer source code:

public class MainDesigner : ParentControlDesigner
{
    private DesignerVerbCollection dvc = new DesignerVerbCollection();
    public override void Initialize(System.ComponentModel.IComponent component)
    {
        base.Initialize(component);

        if (this.Control is MZTabControl)
        {
            this.EnableDesignMode(((MZTabControl)this.Control).TabControlArea, 
                "TabControlArea");
            var uc = (MZTabControl)component;

            foreach (TabPage tbpg in uc.tbBody.TabPages)
            {
                EnableDesignMode(tbpg, tbpg.Name);
            }
        }
    }
}

Before rebuild or clean: Screenshot
After rebuild or clean: Screenshot


Solution

  • The designer of Form cant't see those TabPag controls which you created in the UserControl.

    You can remove all items from TabPages collection of the TabControl in your UserControl. If you need the TabControl have some pages after adding to Form you can add some tab pages in InitializeNewComponent method of designer of your user control. Then user can change those pages or add/remove pages to the TabControl of your UserControl and all tabs and their contents will be serialized because this way the Form designer can see those tabs.

    UserControl1

    Create a public property for the TabControl and decorate it with DesignerSerializationVisibility by passing DesignerSerializationVisibility.Content as value to say the designer serialize the content of control:

    using System.ComponentModel;
    using System.Windows.Forms;
    using System.Windows.Forms.Design;
    [Designer(typeof(UserControl1Designer))]
    public partial class UserControl1 : UserControl
    {
        public UserControl1() { InitializeComponent(); }
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public TabControl MyTabControl 
        {
           get { return this.tabControl1; } 
        }
        private void InitializeComponent()
        {
            this.tabControl1 = new System.Windows.Forms.TabControl();
            this.SuspendLayout();
            this.tabControl1.Name = "tabControl1";
            this.tabControl1.Dock = DockStyle.Fill;
            this.Controls.Add(this.tabControl1);
            this.Name = "UserControl1";
            this.ResumeLayout(true);
        }
        private System.Windows.Forms.TabControl tabControl1;
    }
    

    UserControl1Designer

    Enable the designer of TabControl using EnableDesignMode method of the designer. Also initialize the TabControl by adding 2 TabPage like the job that the original control performs. To do so, you should use IDesignerHost service like below.

    public class UserControl1Designer : ParentControlDesigner
    {
        public override void Initialize(System.ComponentModel.IComponent component)
        {
            base.Initialize(component);
            this.EnableDesignMode(((UserControl1)this.Control).MyTabControl, "MyTabControl");
        }
        public override void InitializeNewComponent(System.Collections.IDictionary values)
        {
            base.InitializeNewComponent(values);
            AddTab();
            AddTab();
        }
        private void AddTab()
        {
            TabControl tabControl = ((UserControl1)this.Control).MyTabControl;
            var svc = (IDesignerHost)this.GetService(typeof(IDesignerHost));
            if (svc != null)
            {
                var tab1 = (TabPage)svc.CreateComponent(typeof(TabPage));
                tab1.Text = tab1.Name;
                tab1.UseVisualStyleBackColor = true;
                tabControl.TabPages.Add(tab1);
                var property = TypeDescriptor.GetProperties(tabControl)["Controls"];
                base.RaiseComponentChanging(property);
                base.RaiseComponentChanged(property, null, null);
            }
        }
    }
    

    Then if you drag UserControl1 from toolbox and add it to the form, you can see the user control contains an editable tab control which contains 2 editable tab pages and all changes will be serialized and be persisted.

    Note

    If you have a single or two pages in the TabContrl of your UserControl and you want to make them editabe, you should create public properties in your UserControl and enable designer of each tab page with name of corresponding property.

    Consider this note from remarks part of EnableDesignMode:

    The child does not directly participate in persistence, but it will if it is exposed as a property of the main control.

    UserControl

    You should have a public property for each TabPage which you want to expose:

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public TabControl MyTabControl
    { 
        get { return this.tabControl1; } 
    }
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public TabPage T1 
    {
        get { return this.tabPage1; } 
    }
    

    Designer

    public class MyUserControl2Designer : ParentControlDesigner
    {
        public override void Initialize(System.ComponentModel.IComponent component)
        {
            base.Initialize(component);
            this.EnableDesignMode(((UserControl2)this.Control).MyTabControl, "MyTabControl");
            this.EnableDesignMode(((UserControl2)this.Control).T1, "T1");
        }
    }