嵌套面板:'孩子'不是这个父母的子控件
我有一个继承自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
你必须先删除该控件,然后将其添加到innerpanel。控制不能在两个通道同时:
void TestPanel2_ControlAdded(object sender, ControlEventArgs e)
{
if (e.Control != innerPanel) {
this.Controls.Remove(e.Control);
innerPanel.Controls.Add(e.Control);
}
}
我不确定是否属实。将控件添加到一个容器似乎会自动将其从已存在的任何容器中移除(我已经通过多种方式测试了该理论)。尽管如此,这是我尝试解决这个问题的第一件事情之一,并没有解决问题。这个错误仍然存在(我甚至在现在再次尝试,确认,事实上它似乎没有任何改变)。 – Cosmicjive 2014-12-07 18:32:15
Hans Passant我指出了正确的方向通过链接到这个讨论:
我还发现了一个示例项目,表明几乎完全控制我想创建:
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。 你想设计了用户控制当你的内板是可移动的和相当大的,但不是当你已经放弃了用户控件上的另一个设计表面
- 为了实现这一点我创建的继承图a的ContentPanel,然后用于自定义设计,以除去在设计时上浆握把根据需要
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
}
}
享受...
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
感谢Hans,这对我有很大帮助。 – Cosmicjive 2014-12-07 21:18:53