【问题标题】:Controls added to TabPage of the TabControl of my UserControl disappear after rebuild添加到我的 UserControl 的 TabControl 的 TabPage 的控件在重建后消失
【发布时间】:2016-08-23 11:12:03
【问题描述】:

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

当我将 UserControl 添加到 Form 并在标签页上添加控件时,一切正常,并且可以正确添加/删除/更改控件,直到我构建项目或保存更改并关闭并重新打开表单。

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

为什么我在UserControl的TabControl的标签页中添加的控件在rebuild后消失了?

我的用户控件源代码:

注意:tbBodyTabControl

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

重建或清理之前:Screenshot
重建或清理后:Screenshot

【问题讨论】:

  • 您发现 [DesignerSerializationVisibility] 属性不起作用的困难方式。如果要序列化内容,则对象必须是可序列化的。 TabControl 不是,所有控件都不是。因此,当重新加载设计器时,内容不可避免地会再次消失。非常不清楚为什么您喜欢 UserControl 作为基类,您似乎没有使用多个子控件。改为从 TabControl 派生您的类,从而陷入成功的深渊。
  • 感谢 hans passant,所有 vs 组件在设计时都无法点击,只有 tabcontrol 是可点击的。我需要一个带有设计时点击事件的用户控件。我必须如何序列化这个 tabcontrol?
  • TabControl 已经有一个 Click 事件,这还不足以成为需要 UserControl 作为基类的理由。只需调用 OnClick() 即可生成事件。
  • 当我说可点击时,我的意思是它在设计时可点击(当您在表单上设计时)例如一个文本框一个用户控件或一个按钮或任何东西。但是,如果我向用户控件添加一个选项卡控件,并且当我通过我提到的步骤在我的表单上使用此用户控件时,它可以单击设计时表单(不是设计时用户控件),并且您使用作为基类是正确的:)
  • 您的TabControlArea 中是否有固定的TabPages 计数,或者应该在设计模式下添加页面?

标签: c# winforms tabcontrol windows-forms-designer designer


【解决方案1】:

Form 的设计者看不到您在UserControl 中创建的那些TabPag 控件。

您可以从UserControlTabControlTabPages 集合中删除所有项目。如果您需要TabControl 在添加到Form 后有一些页面,您可以在用户控件设计器的InitializeNewComponent 方法中添加一些标签页。然后用户可以更改这些页面或将页面添加/删除到您的UserControlTabControl,并且所有选项卡及其内容都将被序列化,因为这样Form 设计人员可以看到这些选项卡。

用户控制1

TabControl创建一个公共属性并用DesignerSerializationVisibility装饰它,通过传递DesignerSerializationVisibility.Content作为值来表示设计者序列化控件的内容:

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 个可编辑的选项卡页,所有更改都将被序列化并被持久化。

注意

如果您的UserControlTabContrl 中有一个或两个页面并且您想让它们成为可编辑的,您应该在您的UserControl 中创建公共属性并启用每个标签页的设计器,其名称为相应的属性。

考虑EnableDesignMode的备注部分中的此注释:

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

用户控制

您应该为要公开的每个 TabPage 拥有一个公共属性:

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

【讨论】:

  • 我测试了这两种方法,它们都有效。
  • 从 form1 中删除现有的用户控件。然后关闭所有设计器,然后清理并重建解决方案。然后将您的用户控件放在没有标签页的Form1 上。然后在Form1 的设计者中添加标签页和内容。并保存表格。关闭并再次打开表单,您将看到您的内容已序列化。
  • 你不需要添加[Serializable]它完全没用,因为控件不可序列化。使用我的示例查看它在没有 Serializable 属性的情况下是否有效。
  • 是的,我也会针对这种情况发布一个示例。
  • 确保您仔细阅读编辑。我向用户控件的设计器添加了一项功能,该功能允许您使用一些可编辑的标签页来初始化 TabControl
猜你喜欢
  • 1970-01-01
  • 2011-11-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多