4

I have use the following code to create a textbox, but the paint method is not triggered at any situation of the textbox. Can you suggest a solution to trigger the OnPaint() ?

public class MyTextBox : TextBox
{
    protected override void OnPaintBackground(PaintEventArgs pevent)
    {
        base.OnPaintBackground(pevent);
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        ControlPaint.DrawBorder(e.Graphics,this.Bounds, Color.Red,ButtonBorderStyle.Solid);
        base.OnPaint(e);
    }

    protected override void OnTextChanged(EventArgs e)
    {
        this.Invalidate();
        this.Refresh();
        base.OnTextChanged(e);
    }
}
TaW
  • 53,122
  • 8
  • 69
  • 111
Venkatesh Ks
  • 92
  • 1
  • 7
  • 2
    Did you debug that it is not hit? Your `DrawBorder` call maybe useless, because you call `base.OnPaint()` _after_ that. So the `TextBox` draws itself again _over_ what you painted before. – René Vogt Jun 21 '16 at 12:26

3 Answers3

22

OnPaint will not be called on a TextBox by default unless you register it as a self-painting control, by making a call to :

SetStyle(ControlStyles.UserPaint, true);

e.g. from your MyTextBox constructor.

Ben Jackson
  • 1,108
  • 6
  • 9
  • 5
    @VenkateshKs If this answered your question please mark it as the answer to help future users who have similar quesitons. – Jarrett Robertson Jun 21 '16 at 12:39
  • 1
    This fixed the triggering event problem but messed up the way textbox operates. – KodFun May 19 '20 at 20:49
  • This may call OnPaint but now it's painted by the system in a tiny font with a tiny caret, and my own OnPaint method gets overdrawn. Switching to a RichTextbox allowed me to paint it myself but the caret is still drawn by the system. – Bip901 Dec 16 '20 at 20:33
  • Like René Vogt has mentioned; Paint Event is NOT Supported by the Default TextBox and using: SetStyle(ControlStyles.UserPaint, true) is NOT Viable. IMHO to customize the TextBox; it is preferrable to create a User Control (derived from a TextBox) for this Purpose. Takes a little work and time but it would work and perform better, than attempting modify the base Control. –  Mar 20 '22 at 16:22
4

You need to switch the calls in your OnPaint

protected override void OnPaint(PaintEventArgs e)
{
    base.OnPaint(e);
    ControlPaint.DrawBorder(e.Graphics, this.Bounds, Color.Red, ButtonBorderStyle.Solid);
}

base.OnPaint() draws the TextBox as usual. If you call DrawBorder before the base call, it is overpainted by the base implementation again.


But according to documentation, the Paint event is not supported by TextBox:

This API supports the product infrastructure and is not intended to be used directly from your code.
Occurs when the control is redrawn. This event is not relevant for this class.

So Ben Jackon's answer should solve that problem.

René Vogt
  • 43,056
  • 14
  • 77
  • 99
1

What I did was create the graphics object after the window receives the WM_PAINT message.

C#

protected override void WndProc(ref Message m)
{
    base.WndProc(m);
    switch (m.Msg)
    {
        case WM_PAINT:
            BackgroundText();
            break;
    }
}

private void BackgroundText()
{
    if (DesignMode)
    {
        using (Graphics G = CreateGraphics())
        {
            TextRenderer.DrawText(G, "Project No.", new Font("Microsoft Sans Serif", 8.25), new Point(3, 1), Color.FromArgb(94, 101, 117));
        }
        return;
    }
    if (string.IsNullOrEmpty(Text))
    {
        using (Graphics G = CreateGraphics())
        {
            Color tColor = FindForm.ActiveControl == this ? Color.FromArgb(94, 101, 117) : SystemColors.Window;
            TextRenderer.DrawText(G, "Project No.", new Font("Microsoft Sans Serif", 8.25), new Point(3, 1), tColor);
        }
    }
}

VB.NET

Protected Overrides Sub WndProc(ByRef m As Message)
    MyBase.WndProc(m)
    Select Case m.Msg
        Case WM_PAINT
            BackgroundText()
    End Select
End Sub

Private Sub BackgroundText()
    If DesignMode Then
        Using G As Graphics = CreateGraphics()
            TextRenderer.DrawText(G, "Project No.", New Font("Microsoft Sans Serif", 8.25), New Point(3, 1), Color.FromArgb(94, 101, 117))
        End Using
        Return
    End If
    If String.IsNullOrEmpty(Text) Then
        Using G As Graphics = CreateGraphics()
            Dim tColor As Color = If(FindForm.ActiveControl Is Me, Color.FromArgb(94, 101, 117), SystemColors.Window)
            TextRenderer.DrawText(G, "Project No.", New Font("Microsoft Sans Serif", 8.25), New Point(3, 1), tColor)
        End Using
    End If
End Sub
John89
  • 45
  • 1
  • 7