嵌套面板:'孩子'不是这个父母的子控件

问题描述:

我有一个继承自Panel的类。它包含嵌套在其中的第二个面板。当控件添加到此控件时,我实际上希望它们添加到内部面板。这里的目标是使用外部面板绘制一个特殊的边框,但是随后能够将内部面板的控件托管,就好像它是任何其他面板一样。嵌套面板:'孩子'不是这个父母的子控件

这里是我使用的基本代码:

public class TestPanel2 : Panel 
{ 
    private Panel innerPanel = new Panel(); 

    public TestPanel2() 
    { 
     this.Controls.Add(innerPanel); 
     this.ControlAdded += new ControlEventHandler(TestPanel2_ControlAdded); 
    } 

    void TestPanel2_ControlAdded(object sender, ControlEventArgs e) 
    { 
     if (e.Control != innerPanel) { 
      innerPanel.Controls.Add(e.Control); 
     } 
    } 
} 

当使用在设计这种控制,拖着子控件(如CheckBox)到它导致设计师报告:

'child' is not a child control of this parent 

我的理论是设计师为了自己的目的调用Controls.SetChildIndex()或Controls.GetChildIndex(),并且这是触发错误。所以,我想加入以下属性添加到该类:

public new ControlCollection Controls 
    { 
     get { return innerPanel.Controls; } 
    } 

当我这样做,我也改变this.Controls的所有内部引用base.Controls。但是,这并没有解决问题。

有没有办法添加一个嵌套的面板,自动接收拖入它的控件?如果我更改代码,以便在运行时将子控件添加到innerControl中,它可以工作,但子控件的位置最终会出错,所以它不是一个很好的解决方案。

UPDATE:

不管出于什么值得注意的是,这里是什么,我试图做一个简单的示意图。我正在创建一个将被其他开发人员使用的工具包。它是一个专门的面板,其中包含一个自定义边框和标题栏。把它看作功能上类似于“GroupBox”控件。我希望他们能够将这个专门的面板拖到他们的表单上,然后在Designer中添加控件。 “innerPanel”需要是自己的面板,这是滚动的唯一区域(当需要滚动时)。

​​3210

+0

http://stackoverflow.com/questions/8186053/how-do-i-provide-designer-support-to-a-tabcontrol-residing-in-a- usercontrol-so/8186389#8186389 – 2014-12-07 19:30:49

+0

感谢Hans,这对我有很大帮助。 – Cosmicjive 2014-12-07 21:18:53

你必须先删除该控件,然后将其添加到innerpanel。控制不能在两个通道同时:

void TestPanel2_ControlAdded(object sender, ControlEventArgs e) 
{ 
    if (e.Control != innerPanel) { 
     this.Controls.Remove(e.Control); 
     innerPanel.Controls.Add(e.Control); 
    } 
} 
+1

我不确定是否属实。将控件添加到一个容器似乎会自动将其从已存在的任何容器中移除(我已经通过多种方式测试了该理论)。尽管如此,这是我尝试解决这个问题的第一件事情之一,并没有解决问题。这个错误仍然存​​在(我甚至在现在再次尝试,确认,事实上它似乎没有任何改变)。 – Cosmicjive 2014-12-07 18:32:15

Hans Passant我指出了正确的方向通过链接到这个讨论:

How do I provide designer support to a TabControl residing in a UserControl, so that I can drag/drop controls onto tab pages?

我还发现了一个示例项目,表明几乎完全控制我想创建:

http://www.codeproject.com/Articles/37830/Designing-Nested-Controls

这里是我的修订的版本控制:

[Designer(typeof(TestUserControlDesigner))] 
public partial class TestPanel3 : UserControl 
{ 
    private Panel innerPanel = new Panel(); 

    public TestPanel3() 
    { 
     InitializeComponent(); 
     this.Controls.Add(innerPanel); 
    } 

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] 
    public Panel ContentPanel 
    { 
     get { return innerPanel; } 
    } 
} 

internal class TestUserControlDesigner : ParentControlDesigner 
{ 
    public override void Initialize(System.ComponentModel.IComponent component) 
    { 
     base.Initialize(component); 
     EnableDesignMode((this.Control as TestPanel3).ContentPanel, "ContentPanel"); 
    } 
} 

这种方法的作品,虽然“innerPanel”可以在设计控制的“拖出来”。但是还有其他解决方案可以解决这个问题,这是一个很好的解决方案。

我知道这已经过去了几个月了,但请参阅此博客条目,了解如何使内部控件成为用户控件的内容控件。它会让你的生活变得容易很多,因为控制只能够放在你的内部面板上。

How can I drop controls within UserControl at Design time? 几件事情要考虑:1。 你想设计了用户控制当你的内板是可移动的和相当大的,但不是当你已经放弃了用户控件上的另一个设计表面

  1. 为了实现这一点我创建的继承图a的ContentPanel,然后用于自定义设计,以除去在设计时上浆握把根据需要
  2. A.下面是外板设计者 - 我实现将它嵌入到外部面板中它可以与被施加到所述外类

    [Designer(typeof(YourUserControl.Designer))] 
    public partial class YourUserControl : UserControl 
    
    #region Designer - Friend class 
    
        /// <summary> 
        /// Exposes the internal panel as content at design time, 
        /// allowing it to be used as a container for other controls. 
        /// 
        /// Adapted 
        /// From: How can I drop controls within UserControl at Design time? 
        /// Link: http://blogs.msdn.com/b/subhagpo/archive/2005/03/21/399782.aspx 
        /// </summary> 
        internal class Designer : ParentControlDesigner 
        { 
         public override void Initialize(IComponent component) 
         { 
          base.Initialize(component); 
    
          var parent = (YourUserControl)component; 
          EnableDesignMode(parent.Content, "Content"); 
         } 
        } 
    
        #endregion 
    

    B.这里是一个需要被添加到外板

    #region Content - Used by the designer class 
    
        /// <summary> 
        /// Defines the control which can act as a container at design time. 
        /// In conjunction with other design time attributes and the designer 
        /// defined below, allows the user control to act as a container at 
        /// design time. This means other controls can be sited on the content 
        /// panel, such as a text boxes or labels, etc. 
        /// </summary> 
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] 
        public ContentPanel Content 
        { 
         get 
         { 
          return this.contentPanel1; 
         } 
        } 
    
        #endregion 
    

    C.这里Content属性像这样一个设计属性来引用是用作内容面板的内部面板。在你的情况下,你需要在下面的代码中切换Dock和Anchor属性。我希望它始终处于停靠状态,而您会希望它始终停留,因为您在帖子中引用的标题和边框。

    using System; 
    using System.Collections; 
    using System.Collections.Generic; 
    using System.ComponentModel; 
    using System.ComponentModel.Design; 
    using System.Linq; 
    using System.Windows.Forms; 
    using System.Windows.Forms.Design; 
    using System.Text; 
    using System.Threading.Tasks; 
    
    namespace j2associates.Tools.Winforms.Controls 
    { 
        [Designer(typeof(ContentPanel.Designer))] 
        public class ContentPanel : Panel 
        { 
         private ScrollableControl _parentScrollableControl; 
    
         public ContentPanel() 
          : base() 
         { 
          // Dock is always fill. 
          this.Dock = DockStyle.Fill; 
         } 
    
         protected override void OnParentChanged(EventArgs e) 
         { 
          base.OnParentChanged(e); 
    
          if (this.Parent != null) 
          { 
           Control parent = this.Parent; 
           while (parent != null && this.Parent.GetType() != typeof(ScrollableControl)) 
           { 
            parent = parent.Parent; 
           } 
           if (parent != null && parent.GetType() == typeof(ScrollableControl)) 
           { 
            _parentScrollableControl = (ScrollableControl)parent; 
    
            // Property value is retrieved from scrollable control panel. 
            this.AutoScroll = _parentScrollableControl.AutoScroll; 
           } 
          } 
         } 
    
         protected override void OnPaint(PaintEventArgs e) 
         { 
          base.OnPaint(e); 
    
          if (_parentScrollableControl != null) 
          { 
           this.AutoScroll = _parentScrollableControl.AutoScroll; 
          } 
         } 
    
         protected override void OnEnter(EventArgs e) 
         { 
          base.OnEnter(e); 
    
          this.AutoScroll = _parentScrollableControl != null ? _parentScrollableControl.AutoScroll : false; 
         } 
    
         #region Designer - Friend class 
    
         /// <summary> 
         /// Allows us to handle special cases at design time. 
         /// </summary> 
         internal class Designer : ParentControlDesigner 
         { 
          private IDesignerHost _designerHost = null; 
          private Control _parent = null; 
    
          #region Overrides 
    
          #region Initialize 
    
          public override void Initialize(IComponent component) 
          { 
           base.Initialize(component); 
    
           // Used to determine whether the content panel is sited on a form or on a user control. 
           _designerHost = (IDesignerHost)this.GetService(typeof(IDesignerHost)); 
           _parent = ((ContentPanel)component).Parent; 
          } 
    
          #endregion 
    
          #region SelectionRules 
    
          public override SelectionRules SelectionRules 
          { 
           get 
           { 
            SelectionRules selectionRules = base.SelectionRules; 
    
            // When hosted on a form, remove all resizing and moving grips at design time 
            // because the content panel is part of a composed user control and it cannot 
            // be moved nor can the dock property change. 
            // 
            // When not hosted on a form, then it is part of a user control which is being 
            // composed and it can be moved or the dock property changed. 
            if (!ReferenceEquals(_designerHost.RootComponent, _parent)) 
            { 
             selectionRules = SelectionRules.Visible | SelectionRules.Locked; 
            } 
    
            return selectionRules; 
           } 
          } 
    
          #endregion 
    
          #region PreFilterProperties 
    
          protected override void PreFilterProperties(System.Collections.IDictionary properties) 
          { 
           base.PreFilterProperties(properties); 
    
           // The Anchor property is not valid for a ContentPanel so just get rid of it. 
           properties.Remove("Anchor"); 
          } 
    
          #endregion 
    
          #region PostFilterProperties 
    
          protected override void PostFilterProperties(System.Collections.IDictionary properties) 
          { 
           // Hide the Anchor property so it cannot be changed by the developer at design time. 
           PropertyDescriptor dockDescriptor = (PropertyDescriptor)properties["Dock"]; 
           dockDescriptor = TypeDescriptor.CreateProperty(dockDescriptor.ComponentType, dockDescriptor, new Attribute[] { new BrowsableAttribute(false), new EditorBrowsableAttribute(EditorBrowsableState.Never)}); 
           properties[dockDescriptor.Name] = dockDescriptor; 
    
           // Hide the AutoScroll property so it cannot be changed by the developer at design time 
           // because it is set from the nearest panel of type scrollable control. 
           PropertyDescriptor autoScrollDescriptor = (PropertyDescriptor)properties["AutoScroll"]; 
           autoScrollDescriptor = TypeDescriptor.CreateProperty(autoScrollDescriptor.ComponentType, autoScrollDescriptor, new Attribute[] { new ReadOnlyAttribute(true) }); 
           properties[autoScrollDescriptor.Name] = autoScrollDescriptor; 
    
           // Make the Name property read only so it cannot be changed by the developer at design time 
           // because it is set from the nearest panel of type scrollable control. 
           PropertyDescriptor nameDescriptor = (PropertyDescriptor)properties["Name"]; 
           nameDescriptor = TypeDescriptor.CreateProperty(nameDescriptor.ComponentType, nameDescriptor, new Attribute[] { new ReadOnlyAttribute(true) }); 
           properties[nameDescriptor.Name] = nameDescriptor; 
    
           // Always call the base method last. 
           base.PostFilterProperties(properties); 
          } 
    
          #endregion 
    
          #endregion 
         } 
    
         #endregion 
        } 
    } 
    

    享受...

开始=>