C# 添加到my UserControl的TabControl的TabPage的控件在重建后消失

C# 添加到my UserControl的TabControl的TabPage的控件在重建后消失,c#,winforms,tabcontrol,windows-forms-designer,designer,C#,Winforms,Tabcontrol,Windows Forms Designer,Designer,我有一个UserControl,其中包含一个TabControl。我启用了TabControl及其TabPages的设计器,因此用户可以添加/删除/修改选项卡页面,并向选项卡页面添加控件 当我将我的UserControl添加到表单并在选项卡页面上添加控件时,这是正常的,可以正确添加/删除/更改控件,直到我生成项目或保存更改并关闭并重新打开表单 当我构建项目时,我在选项卡页面中所做的所有更改以及添加到选项卡页面的每个控件都将被删除。控件存在于designer.cs上,但它们不显示在选项卡页面上 为

我有一个
UserControl
,其中包含一个
TabControl
。我启用了
TabControl
及其
TabPages
的设计器,因此用户可以添加/删除/修改选项卡页面,并向选项卡页面添加控件

当我将我的
UserControl
添加到
表单
并在选项卡页面上添加控件时,这是正常的,可以正确添加/删除/更改控件,直到我生成项目或保存更改并关闭并重新打开表单

当我构建项目时,我在选项卡页面中所做的所有更改以及添加到选项卡页面的每个控件都将被删除。控件存在于
designer.cs
上,但它们不显示在选项卡页面上

为什么我添加到UserControl的TabControl选项卡页面的控件在重建后消失

我的用户控制源代码:

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);
            }
        }
    }
}
注意:
tbBody
是一个
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;
        }
    }
}
我的设计器源代码:

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);
            }
        }
    }
}
重建或清理前:

重建或清理后:

表单的设计者看不到您在
UserControl
中创建的
TabPag
控件

您可以从
UserControl
中的
TabControl
集合中删除所有项。如果您需要
选项卡控件
在添加到
表单
后有一些页面,您可以在用户控件的设计器的
初始化组件
方法中添加一些选项卡页面。然后,用户可以更改这些页面或将页面添加/删除到
UserControl
TabControl
中,所有选项卡及其内容都将被序列化,因为这样
表单
设计器可以看到这些选项卡

UserControl1

选项卡控件
创建一个公共属性,并通过将
DesignerSerializationVisibility.Content
传递为值来使用
DesignerSerializationVisibility
装饰它,以表示设计器序列化控件的内容:

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

使用设计器的
EnableDesignMode
方法启用
TabControl
的设计器。还可以像原始控件执行的作业一样,通过添加2个
TabPage
来初始化
TabControl
。为此,您应该使用如下所示的
IDesignerHost
服务

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);
        }
    }
}
然后,如果从工具箱中拖动
UserControl1
,并将其添加到表单中,则可以看到用户控件包含一个可编辑选项卡控件,该控件包含2个可编辑选项卡页面,所有更改都将序列化并持久化

注 如果您的
UserControl
tabcontroll
中有一个或两个页面,并且您希望对其进行编辑,则应在
UserControl
中创建公共属性,并使用相应属性的名称启用每个选项卡页面的设计器

从以下部分的备注中考虑此注释:

子对象不直接参与持久性,但如果 它作为主控件的属性公开

用户控制

对于要公开的每个
选项卡页
,您都应该有一个公共属性:

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

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");
    }
}

您很难发现[DesignerSerializationVisibility]属性不起作用。如果要序列化内容,则对象必须是可序列化的。TabControl不是,所有控件都不是。因此,当重新加载设计器时,内容不可避免地再次消失。不清楚为什么您喜欢将UserControl作为基类,因为您似乎没有使用多个子控件。通过从TabControl派生类而获得成功。谢谢hans passant,所有vs组件在设计时都不可单击,只有TabControl是可单击的。我需要一个带有设计时单击事件的usercontrol。我必须如何序列化这个tabcontrol?tabcontrol已经有了一个Click事件,没有足够的理由需要UserControl作为基类。只需调用OnClick()生成事件。当我说clickable时,我指的是它在设计时可单击(当您在表单上设计它时),例如一个文本框、一个用户控件或一个按钮或任何东西。但是如果我在usercontrol中添加一个tabcontrol,并且当我在表单上使用这个usercontrol并执行上述步骤时,它可以单击设计时表单(而不是设计时usercontrol),关于使用作为基类,您是对的:)您的
TabControlArea
中是否有固定数量的
TabPages
,或者应该在设计模式下添加页面?我测试了这两种方法,并且它们都有效。从form1中删除现有的用户控件。然后关闭所有设计器,然后清理并重建解决方案。然后将用户控件放在没有选项卡页的
Form1
上。然后在
Form1的dsigner中添加选项卡页面和内容。然后保存表单。再次关闭并打开表单,您将看到您的内容已序列化。您不需要添加
[Serializable]
,这完全没有用,因为控件处于不可序列化状态。请使用我的示例查看它在没有
Serializable
属性的情况下是否有效。是的,我也将发布一个此案例的示例。请确保仔细阅读编辑。我在用户控件的设计器中添加了一个功能,允许您在一些选项卡页面可编辑时初始化
TabControl