我已经创建了一个自定义TextBox
类,以基于this other SO post在我的应用程序中有一个带有自定义边框的文本框。如果我在表单设计器中设置了任何新的自定义属性,它们会暂时显示,直到更改控件焦点为止,并且在运行应用程序时,不会显示新的边框设置。我确实更新了表单的InitializeComponent
方法,以便文本框初始化一个新的BorderedTextBox
而不是TextBox
。有人知道这是怎么回事吗?
public class BorderedTextBox : TextBox
{
private Color _borderColor = Color.Black;
private int _borderWidth = 2;
private int _borderRadius = 5;
public BorderedTextBox() : base()
{
InitializeComponent();
this.Paint += this.BorderedTextBox_Paint;
}
public BorderedTextBox(int width, int radius, Color color) : base()
{
this._borderWidth = Math.Max(1, width);
this._borderColor = color;
this._borderRadius = Math.Max(0, radius);
InitializeComponent();
this.Paint += this.BorderedTextBox_Paint;
}
public Color BorderColor
{
get => this._borderColor;
set
{
this._borderColor = value;
DrawTextBox();
}
}
public int BorderWidth
{
get => this._borderWidth;
set
{
if (value > 0)
{
this._borderWidth = Math.Min(value, 10);
DrawTextBox();
}
}
}
public int BorderRadius
{
get => this._borderRadius;
set
{ // Setting a radius of 0 produces square corners...
if (value >= 0)
{
this._borderRadius = value;
this.DrawTextBox();
}
}
}
private void BorderedTextBox_Paint(object sender, PaintEventArgs e) => DrawTextBox(e.Graphics);
private void DrawTextBox() => this.DrawTextBox(this.CreateGraphics());
private void DrawTextBox(Graphics g)
{
Brush borderBrush = new SolidBrush(this.BorderColor);
Pen borderPen = new Pen(borderBrush, (float)this._borderWidth);
Rectangle rect = new Rectangle(
this.ClientRectangle.X,
this.ClientRectangle.Y,
this.ClientRectangle.Width - 1,
this.ClientRectangle.Height - 1);
// Clear text and border
g.Clear(this.BackColor);
// Drawing Border
g.DrawRoundedRectangle(
borderPen,
(0 == this._borderWidth % 2) ? rect.X + this._borderWidth / 2 : rect.X + 1 + this._borderWidth / 2,
rect.Y,
rect.Width - this._borderWidth,
(0 == this._borderWidth % 2) ? rect.Height - this._borderWidth / 2 : rect.Height - 1 - this._borderWidth / 2,
(float)this._borderRadius);
}
#region Component Designer generated code
/// <summary>Required designer variable.</summary>
private System.ComponentModel.IContainer components = null;
/// <summary>Clean up any resources being used.</summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
components.Dispose();
base.Dispose(disposing);
}
/// <summary>Required method for Designer support - Don't modify!</summary>
private void InitializeComponent() => components = new System.ComponentModel.Container();
#endregion
}
答案 0 :(得分:3)
您需要覆盖WndProc:
private const int WM_PAINT = 0x000F;
protected override void WndProc( ref Message m ) {
if(m.Msg == WM_PAINT ) {
base.WndProc( ref m );
Graphics gr = this.CreateGraphics();
//draw what you want
gr.Dispose();
return;
}
base.WndProc( ref m );
}
工作正常,没有任何问题。它虽然吸引客户区。绘制自定义边框的完整版本,textbox
必须具有边框:
[DllImport( "user32.dll" )]
static extern IntPtr GetWindowDC( IntPtr hWnd );
[DllImport( "user32.dll" )]
static extern bool ReleaseDC( IntPtr hWnd, IntPtr hDC );
[DllImport( "gdi32.dll" )]
static extern bool FillRgn( IntPtr hdc, IntPtr hrgn, IntPtr hbr );
[DllImport( "gdi32.dll" )]
static extern IntPtr CreateRectRgn( int nLeftRect, int nTopRect, int nRightRect,
int nBottomRect );
[DllImport( "gdi32.dll" )]
static extern IntPtr CreateSolidBrush( uint crColor );
[DllImport( "gdi32.dll" )]
static extern bool DeleteObject( IntPtr hObject );
private const int WM_NCPAINT = 0x0085;
private const int WM_PAINT = 0x000F;
private const int RGN_DIFF = 0x4;
private int p_border = 2;
protected override void WndProc( ref Message m ) {
if(m.Msg == WM_PAINT ) {
base.WndProc( ref m );
IntPtr hdc = GetWindowDC( this.Handle ); //gr.GetHdc();
IntPtr rgn = CreateRectRgn( 0, 0, this.Width, this.Height );
IntPtr brush = CreateSolidBrush( 0xFF0000 ); //Blue : B G R
CombineRgn( rgn, rgn, CreateRectRgn( p_border, p_border, this.Width - p_border,
this.Height - p_border ), RGN_DIFF );
FillRgn( hdc, rgn, brush );
ReleaseDC( this.Handle, hdc );
DeleteObject( rgn );
DeleteObject( brush );
m.Result = IntPtr.Zero;
return;
}
if( m.Msg == WM_NCPAINT ) {
return;
}
base.WndProc( ref m );
}
答案 1 :(得分:1)
Winforms TextBox
是一个旧控件,我认为甚至可以追溯到.Net框架之前。
它不支持所有者绘图,正如在MSDN上看到的那样,Paint
和OnPaint
都没有文件记录。
是的,您可以对它们进行编码,是的,它们会产生一些效果。但是TextBox
不能遵循正常规则,并且会在不触发绘画事件的情况下使您的绘图混乱。
可能您可以将自己挂在Windows消息队列(WndProc
)中,但是通常不建议这样做,尤其是对于带有边框的装饰。
通常,最简单的解决方案是将TextBox
嵌套在Panel
中,然后让Panel
绘制出漂亮的Border
。