代码之家  ›  专栏  ›  技术社区  ›  Jim Fell

自定义文本框未绘制

  •  1
  • Jim Fell  · 技术社区  · 8 年前

    我已经定了个规矩 TextBox 类在我的应用程序中具有自定义边框的文本框,基于 this other SO post . 如果我在窗体设计器中设置了任何新的自定义属性,它们会立即出现,直到我更改控件焦点,并且当我运行应用程序时,不会显示新的边框设置。我更新了我的表格 InitializeComponent BorderedTextBox 而不是 . 有人知道这里怎么了吗?

    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
    }
    
    2 回复  |  直到 8 年前
        1
  •  1
  •   TaW    8 年前

    Winforms公司 TextBox 是一个遗留控件,我认为甚至可以追溯到.Net框架之前。

    它不支持所有者绘图,正如您在 MSDN 也不 Paint OnPaint 记录在案。

    是的,你可以编码它们,是的,它们会有一些效果。但是 文本框 不按正常规则玩,会在不触发绘制事件的情况下弄乱绘图。

    您可以将自己挂接到windows消息队列中( WndProc )但一般不建议这样做,特别是像用边框装饰的东西。

    文本框 在一个 Panel 画一张漂亮的画 Border

        2
  •  3
  •   γηράσκω δ' αεί πολλά διδασκόμε    8 年前

    您需要覆盖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 );
    }