我遇到了同样的问题,经过一番挖掘后,我得到了这个控件,它可以用来代替标签。已知问题:单击时,聚焦的控件会失去焦点。这可以在 TableLayoutPanel 中使用,也可以独立使用。
public class LabelTextBox : System.Windows.Forms.TextBox
{
private const int WM_NCPAINT = 0x85;
private const int WM_SETFOCUS = 0x07;
private const int WM_ENABLE = 0x0A;
private const int WM_SETCURSOR = 0x20;
[StructLayout(LayoutKind.Sequential)]
private struct RECT
{
// https://www.pinvoke.net/default.aspx/Structures/RECT.html
}
[StructLayout(LayoutKind.Sequential)]
private struct POINT
{
// https://www.pinvoke.net/default.aspx/Structures/POINT.html
}
public LabelTextBox()
{
// Disable some TextBox interactions, so it is intact as the Label
this.ReadOnly = true;
this.TabStop = false;
}
[DllImport("user32")]
private static extern IntPtr GetWindowDC(IntPtr hwnd);
[DllImport("user32")]
private static extern bool GetClientRect(IntPtr hwnd, out RECT rectangle);
[DllImport("user32")]
private static extern bool GetWindowRect(IntPtr hwnd, out RECT rectangle);
[DllImport("user32.dll")]
static extern bool ClientToScreen(IntPtr hWnd, ref POINT lpPoint);
protected override void WndProc(ref Message m)
{
// Disable some TextBox interactions, so it is intact as the Label
if (m.Msg == WM_SETFOCUS || m.Msg == WM_ENABLE || m.Msg == WM_SETCURSOR)
return;
// When the boreder should be painted
if (m.Msg == WM_NCPAINT)
{
// Get the rect of the client area in the screen coordinates.
var clientOrigin = new POINT(0, 0);
ClientToScreen(Handle, ref clientOrigin);
GetClientRect(Handle, out var clientRect);
clientRect.X = clientOrigin.X;
clientRect.Y = clientOrigin.Y;
// Get the rect of the window area in the screen coordinates.
GetWindowRect(Handle, out var windowRect);
// Calculate the rect of the client area in the window coordinates.
// This will be our clipping area, because we want to paint only the border.
var clip = new Rectangle(
clientRect.Left - windowRect.Left,
clientRect.Top - windowRect.Top,
clientRect.Width,
clientRect.Height
);
// Get the Graphics, set the clip and fill with the BackColor.
var dc = GetWindowDC(Handle);
using (Graphics g = Graphics.FromHdc(dc))
{
g.SetClip(clip, CombineMode.Exclude);
g.FillRectangle(new SolidBrush(BackColor), 0, 0, windowRect.Width, windowRect.Height);
}
return;
}
base.WndProc(ref m);
}
}
结果:
100 %
200 %
我通过 TableLayoutPanel 中那些糟糕的解决方案得出了这个结论:
- 垂直居中——对齐相当稳定,但无法对齐基线。
- 通过填充进行微调 - 在较高 DPI 上仍然不够稳定。
- 使用无边框文本框代替标签 - 无边框文本框的对齐方式与标签相同。
该解决方案的灵感来自于:
- https://stackoverflow.com/a/27027829/2408668
- https://stackoverflow.com/a/74106039/2408668