我能想到几个解决方案,包括以下几种:
- 使用
TableLayoutPanel 的填充
- 使用装饰器和字形
- 创建具有标题和可编辑内容的自定义面板
我认为第一个解决方案很适合您,但其他解决方案也有一些要点。
我也可以想到一个基于NativeWindow 的解决方案,就像在ErrorProvider 中实现的那样,但是它使帖子太长了,而现有的选项已经足够好了。所以,如果你想追求这个想法,我把它留给你。
解决方案 1 - 使用 TableLayoutPanel 的填充
此解决方案适用于设计时和运行时
TableLayoutPanel 有一个Padding 属性,它的布局引擎尊重填充井。您可以使用填充区域来呈现您想要的任何内容:
public class MyTLP : TableLayoutPanel
{
public MyTLP()
{
Padding = new Padding(0, 30, 0, 0);
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
e.Graphics.FillRectangle(Brushes.Orange,
new Rectangle(0, 0, ClientRectangle.Width, Padding.Top));
}
}
解决方案 2 - 使用 Adorner 和 Glyph
此解决方案仅用于设计时
对于设计时渲染,我将使用Adorner 和Glyph 处理它。
如果我在创建我的自定义设计器,所有代码都属于控件设计器,但是由于您不想为TableLayoutPanel创建新的控件设计器,那么和我injected a new custom action in the action lists一样,这里我'会得到BehaviorService,我会在设计时向控件的装饰器注入一个装饰器,这将是结果:
其行为与其他字形非常相似,它会在控件调整大小时自动调整大小,您无需在设计时执行任何特定操作来处理调整大小。
请注意:这是一个设计时的解决方案,而绘画只是在设计师那里完成。如果您需要运行时解决方案,则需要完全不同的解决方案。
代码如下:
using System;
using System.ComponentModel.Design;
using System.Drawing;
using System.Windows.Forms;
using System.Windows.Forms.Design;
using System.Windows.Forms.Design.Behavior;
public class MyTLP : TableLayoutPanel
{
private IDesignerHost designerHost;
private BehaviorService behaviorService;
protected override void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
if (DesignMode && Site != null)
{
designerHost = Site.GetService(typeof(IDesignerHost)) as IDesignerHost;
behaviorService = designerHost?.GetService(typeof(BehaviorService))
as BehaviorService;
if (behaviorService != null)
{
var adorner = new Adorner();
behaviorService.Adorners.Insert(0, adorner);
adorner.Glyphs.Add(new MyTLPGlypg(behaviorService, this));
}
}
}
}
class MyTLPGlypg : Glyph
{
Control control;
BehaviorService behaviorSvc;
public MyTLPGlypg(BehaviorService behaviorSvc, Control control) :
base(new MyBehavior())
{
this.behaviorSvc = behaviorSvc;
this.control = control;
}
public override Rectangle Bounds
{
get
{
var edge = behaviorSvc.ControlToAdornerWindow(control);
var h = 30;
return new Rectangle(edge.X, edge.Y - h, control.Size.Width, h);
}
}
public override Cursor GetHitTest(Point p)
{
//Uncomment if you want to attach a specific behavior
//if (Bounds.Contains(p)) return Cursors.Hand;
return null;
}
public override void Paint(PaintEventArgs pe)
{
pe.Graphics.FillRectangle(Brushes.Orange, Bounds);
}
}
class MyBehavior : Behavior
{
public override bool OnMouseUp(Glyph g, MouseButtons button)
{
//Do something and return true, meand eventhandled
return true;
}
}
注意:
要详细了解锚点、字形和行为,请查看以下链接:
解决方案 3 - 创建自定义面板,具有标题和可编辑内容
您可以创建具有标题和可编辑内容的自定义面板。然后在设计时禁止用户将内容放在标题部分:
为此,您需要创建一个新设计器,通过调用EnableDesignMode 方法在设计时启用内部面板。然后对于内部面板,您需要创建一个设计器,该设计器禁用移动、调整大小并从设计器中删除一些属性。
我已经在这里发布了详细的答案:UserControl with header and content - Allow dropping controls in content panel and Prevent dropping controls in header at design time