我有一个继承自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);
}
}
}
在Designer中使用此控件时,将子控件(例如CheckBox)拖入其中会导致设计器报告:
'child' is not a child control of this parent
我的理论是Designer为了自己的目的而调用Controls.SetChildIndex()或Controls.GetChildIndex(),这就是触发错误。所以我尝试将以下属性添加到类中:
public new ControlCollection Controls
{
get { return innerPanel.Controls; }
}
当我这样做时,我也改变了this.Controls to base.Controls的所有内部引用。但是,这并没有解决问题。
有没有办法添加一个自动接收拖入控件的嵌套面板?如果我更改代码,以便子控件只在运行时添加到innerControl,它可以工作,但子控件的位置最终是错误的,所以它不是一个解决方案。
更新
无论价值多少,这里都是我想要做的简化图。我正在创建一个将由其他开发人员使用的工具包。它是一个包含自定义边框和标题栏的专用面板。可以认为它在功能上类似于“GroupBox”控件。我希望他们能够将这个专用面板拖到他们的表单上,然后在Designer中添加控件。 “innerPanel”需要是它自己的面板,因此它是滚动的唯一区域(当需要滚动时)。
title block panel diagram http://cosmicjive.net/tempimages/NestedPanel.png
答案 0 :(得分:0)
您必须先删除控件,然后将其添加到内部面板。控件不能同时位于两个通道上:
void TestPanel2_ControlAdded(object sender, ControlEventArgs e)
{
if (e.Control != innerPanel) {
this.Controls.Remove(e.Control);
innerPanel.Controls.Add(e.Control);
}
}
答案 1 :(得分:0)
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"可以"被拖出" Designer中的控件。但是对于这个问题还有其他解决方案,否则这是一个很好的解决方案。
答案 2 :(得分:0)
我知道这已有几个月了,但请参阅此博客文章,了解如何使内部控件成为用户控件的内容控件。它将使您的生活变得更加轻松,因为控件只能放在您的内部面板上。
How can I drop controls within UserControl at Design time? 需要考虑的几件事: 1.在设计用户控件时,您希望内部面板可移动且相当大,但是当您将UserControl放在另一个设计图面上时则不行。
一个。这是外部面板的设计者 - 我的实现将它嵌套在外部面板中,因此可以使用类似于Designer的属性来引用它,该属性应用于外部类
[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中。以下是需要添加到外部面板的Content属性
#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
℃。这是用作内容面板的内部面板。在您的情况下,您需要在下面的代码中切换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
}
}
...享受