Пользовательский TextBox Не Рисование - PullRequest
0 голосов
/ 02 октября 2018

Я создал собственный класс TextBox, чтобы в моем приложении было текстовое поле с настраиваемой рамкой на основе этого другого сообщения SO .Если я устанавливаю какие-либо новые пользовательские свойства в конструкторе форм, они появляются на мгновение, пока я не изменю фокус управления, и при запуске приложения новые параметры границ не отображаются.Я обновил метод 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
}

Ответы [ 2 ]

0 голосов

Вам нужно переопределить 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 );
}
0 голосов
/ 02 октября 2018

Winforms TextBox - это устаревший элемент управления, я думаю, даже с давних времен до .Net framework.

Он не поддерживает рисование владельцем и, как видно на MSDN ни Paint, ни OnPaint не документированы для работы.

Да, вы можете их кодировать, и да, они будут иметь некоторый эффект.Но TextBox не играет по обычным правилам и испортит ваш рисунок, не вызывая событие рисования.

Возможно, вы можете подключиться к очереди сообщений Windows (WndProc), но обычно это не так.рекомендуется, особенно для чего-то вроде украшения его рамкой.

Обычно вложение TextBox в Panel и разрешение Panel рисовать хороший Border - самое простое решение ..

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...