C# 嵌套面板:';儿童';不是此父级的子控件
我有一个从Panel继承的类。它包含嵌套在其中的第二个面板。当控件添加到此控件时,我实际上希望它们添加到内部面板。这里的目标是使用外部面板绘制一个特殊的边框,但随后能够在内部面板内部承载控件,就像它是任何其他面板一样 以下是我使用的基本代码:C# 嵌套面板:';儿童';不是此父级的子控件,c#,panel,C#,Panel,我有一个从Panel继承的类。它包含嵌套在其中的第二个面板。当控件添加到此控件时,我实际上希望它们添加到内部面板。这里的目标是使用外部面板绘制一个特殊的边框,但随后能够在内部面板内部承载控件,就像它是任何其他面板一样 以下是我使用的基本代码: public class TestPanel2 : Panel { private Panel innerPanel = new Panel(); public TestPanel2() { this.Contro
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);
}
}
}
在设计器中使用此控件时,将子控件(如复选框)拖动到其中会导致设计器报告:
'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中,它会起作用,但子控件的位置最终会出错,因此这不是一个很好的解决方案
更新:
不管它值多少钱,这里有一个我正在尝试做的简化图表。我正在创建一个工具包,供其他开发人员使用。它是一个包含自定义边框和标题栏的专用面板。可以认为它在功能上类似于“GroupBox”控件。我希望他们能够将这个专门的面板拖到窗体上,然后在设计器中添加控件。“innerPanel”需要是它自己的面板,以便它是唯一滚动的区域(当需要滚动时)
(来源:)您必须先删除控件,然后将其添加到innerpanel。控件不能同时位于两个通道上:
void TestPanel2_ControlAdded(object sender, ControlEventArgs e)
{
if (e.Control != innerPanel) {
this.Controls.Remove(e.Control);
innerPanel.Controls.Add(e.Control);
}
}
通过链接到此讨论为我指明了正确的方向:
我还发现了一个示例项目,它演示了我试图创建的几乎完全相同的控件:
以下是我对控件的修订版本:
[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”可以在设计器中“拖出”控件,但这种方法是有效的。但是对于这个问题还有其他的解决方案,这是一个很好的解决方案。我知道这已经有好几个月了,但是请看这篇关于如何使您的内部控制成为用户控制的内容控制的博客文章。这将使你的生活更加轻松,因为控制装置只能放在你的内面板上 需要考虑的几件事: 1.在设计用户控件时,您希望内部面板是可移动的和可调整大小的,但在将用户控件放到另一个设计图面上时,则不希望这样
[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
[Designer(typeof(YourUserControl.Designer))]
公共部分类YourUserControl:UserControl
#区域设计器-朋友类
///
///在设计时将内部面板作为内容公开,
///允许它用作其他控件的容器。
///
///改编
///From:如何在设计时将控件放置在UserControl中?
///链接:http://blogs.msdn.com/b/subhagpo/archive/2005/03/21/399782.aspx
///
内部类设计器:ParentControlDesigner
{
公共覆盖无效初始化(IComponent组件)
{
初始化(组件);
var parent=(YourUserControl)组件;
EnableDesignMode(parent.Content,“Content”);
}
}
#端区
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
#区域内容-由designer类使用
///
///定义可在设计时用作容器的控件。
///与其他设计时属性和设计器结合使用
///定义如下,允许用户控件在
///设计时间。这意味着可以在内容上放置其他控件
///面板,如文本框或标签等。
///
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
公共内容面板内容
{
得到
{
返回此文件。contentPanel1;
}
}
#端区
C.这是用作内容面板的内面板。在您的情况下,您需要在下面的代码中切换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
}
}
使用系统;
使用系统集合;
使用System.Collections.Generic;
使用系统组件模型;
使用System.ComponentModel.Design;
使用System.Linq;
使用System.Windows.Forms;
使用System.Windows.Forms.Design;
使用系统文本;
使用System.Threading.Tasks;
命名空间j2associates.Tools.Winforms.Controls
{
[设计器(typeof(ContentPanel.Designer))]
公共类ContentPanel:面板
{
私有ScrollableControl _parentScrollableControl;
公共内容小组()
:base()
{
//码头总是满的。
this.Dock=DockStyle.Fill;
}
受保护的覆盖无效OnParentChanged(事件参数e)
{
基数:1(e);
如果(this.Parent!=null)
{
控制父项=此。父项;
while(parent!=null&&this.parent.GetType()!=typeof(ScrollableControl))
{
父=父。父;
}