我可以想到一些解决方案,包括以下内容:
- 使用 Padding
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
,那么就像我在操作列表中注入新的自定义操作一样,这里我'会得到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
方法在设计时启用内部面板。然后对于内部面板,您需要创建一个设计器,该设计器禁用移动、调整大小并从设计器中删除一些属性。
我在这里发布了一个详细的答案:带有标题和内容的用户控件 - 允许在内容面板中放置控件并防止在设计时在标题中放置控件