Raggy Shrestha
Raggy Shrestha

Reputation: 445

Change the borderColor of the TextBox

How can I change the BorderColor of the Textbox when a user Clicks on it or focuses on it?

Upvotes: 32

Views: 157649

Answers (8)

Ahmed Osama
Ahmed Osama

Reputation: 438

enter image description here

Here is my complete Flat TextBox control that supports themes including custom border colors in normal and focused states.

The control uses the same concept mentioned by Reza Aghaei https://stackoverflow.com/a/38405319/5514131 ,however the FlatTextBox control is more customizable and flicker-free.

The control handles the WM_NCPAINT window message in a better way to help eliminate flicker.

Protected Overrides Sub WndProc(ByRef m As Message)

    If m.Msg = WindowMessage.WM_NCPAINT AndAlso _drawBorder AndAlso Not DesignMode Then 'Draw the control border

        Dim w As Integer
        Dim h As Integer
        Dim clip As Rectangle
        Dim hdc As IntPtr

        Dim clientRect As RECT = Nothing
        GetClientRect(Handle, clientRect)

        Dim windowRect As RECT = Nothing
        GetWindowRect(Handle, windowRect)

        w = windowRect.Right - windowRect.Left
        h = windowRect.Bottom - windowRect.Top

        clip = New Rectangle(CInt((w - clientRect.Right) / 2), CInt((h - clientRect.Bottom) / 2), clientRect.Right, clientRect.Bottom)

        hdc = GetWindowDC(Handle)

        Using g As Graphics = Graphics.FromHdc(hdc)

            g.SetClip(clip, CombineMode.Exclude)

            Using sb = New SolidBrush(BackColor)
                g.FillRectangle(sb, 0, 0, w, h)
            End Using

            Using p = New Pen(If(Focused, _borderActiveColor, _borderNormalColor), BORDER_WIDTH)
                g.DrawRectangle(p, 0, 0, w - 1, h - 1)
            End Using

        End Using

        ReleaseDC(Handle, hdc)

        Return

    End If

    MyBase.WndProc(m)

End Sub

I have removed the default BorderStyle property and replaced it with a simple boolean DrawBorder property that controls whether to draw a border around the control or not.

Use the BorderNormalColor property to specify the border color when the TextBox has no focus, and the BorderActiveColor property to specify the border color when the control receives focus.

The FlatTextBox comes with two themes VS2019 Dark and VS2019 Light, use the Theme property to switch between them.

Complete FlatTextBox control code written in VB.NET https://gist.github.com/ahmedosama007/37fe2004183a51a4ea0b4a6dcb554176

Upvotes: 1

user3314233
user3314233

Reputation: 43

With PictureBox1
    .Visible = False
    .Width = TextBox1.Width + 4
    .Height = TextBox1.Height + 4
    .Left = TextBox1.Left - 2
    .Top = TextBox1.Top - 2
    .SendToBack()
    .Visible = True
End With

Upvotes: 0

Moory Pc
Moory Pc

Reputation: 910

set Text box Border style to None then write this code to container form "paint" event

private void Form1_Paint(object sender, PaintEventArgs e)
{
    System.Drawing.Rectangle rect = new Rectangle(TextBox1.Location.X, 
    TextBox1.Location.Y, TextBox1.ClientSize.Width, TextBox1.ClientSize.Height);
                
                rect.Inflate(1, 1); // border thickness
                System.Windows.Forms.ControlPaint.DrawBorder(e.Graphics, rect, 
    Color.DeepSkyBlue, ButtonBorderStyle.Solid);
}

Upvotes: 0

PraveenVenu
PraveenVenu

Reputation: 8337

try this

bool focus = false;
private void Form1_Paint(object sender, PaintEventArgs e)
{
    if (focus)
    {
        textBox1.BorderStyle = BorderStyle.None;
        Pen p = new Pen(Color.Red);
        Graphics g = e.Graphics;
        int variance = 3;
        g.DrawRectangle(p, new Rectangle(textBox1.Location.X - variance, textBox1.Location.Y - variance, textBox1.Width + variance, textBox1.Height +variance ));
    }
    else
    {
        textBox1.BorderStyle = BorderStyle.FixedSingle;
    }
}

private void textBox1_Enter(object sender, EventArgs e)
{
    focus = true;
    this.Refresh();
}

private void textBox1_Leave(object sender, EventArgs e)
{
    focus = false;
    this.Refresh();
}

Upvotes: 21

Reza Aghaei
Reza Aghaei

Reputation: 125197

You can handle WM_NCPAINT message of TextBox and draw a border on the non-client area of control if the control has focus. You can use any color to draw border:

using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
public class ExTextBox : TextBox
{
    [DllImport("user32")]
    private static extern IntPtr GetWindowDC(IntPtr hwnd);
    private const int WM_NCPAINT = 0x85;
    protected override void WndProc(ref Message m)
    {
        base.WndProc(ref m);
        if (m.Msg == WM_NCPAINT && this.Focused)
        {
            var dc = GetWindowDC(Handle);
            using (Graphics g = Graphics.FromHdc(dc))
            {
                g.DrawRectangle(Pens.Red, 0, 0, Width - 1, Height - 1);
            }
        }
    }
}

Result

The painting of borders while the control is focused is completely flicker-free:

Change TextBox border color on focus

BorderColor property for TextBox

In the current post I just change the border color on focus. You can also add a BorderColor property to the control. Then you can change border-color based on your requirement at design-time or run-time. I've posted a more completed version of TextBox which has BorderColor property: in the following post:

Change Textbox border color

Upvotes: 50

Mike de Klerk
Mike de Klerk

Reputation: 12328

Using OnPaint to draw a custom border on your controls is fine. But know how to use OnPaint to keep efficiency up, and render time to a minimum. Read this if you are experiencing a laggy GUI while using custom paint routines: What is the right way to use OnPaint in .Net applications?

Because the accepted answer of PraVn may seem simple, but is actually inefficient. Using a custom control, like the ones posted in the answers above is way better.

Maybe the performance is not an issue in your application, because it is small, but for larger applications with a lot of custom OnPaint routines it is a wrong approach to use the way PraVn showed.

Upvotes: 3

LarsTech
LarsTech

Reputation: 81620

WinForms was never good at this and it's a bit of a pain.

One way you can try is by embedding a TextBox in a Panel and then manage the drawing based on focus from there:

public class BorderTextBox : Panel {
  private Color _NormalBorderColor = Color.Gray;
  private Color _FocusBorderColor = Color.Blue;

  public TextBox EditBox;

  public BorderTextBox() {
    this.DoubleBuffered = true;
    this.Padding = new Padding(2);

    EditBox = new TextBox();
    EditBox.AutoSize = false;
    EditBox.BorderStyle = BorderStyle.None;
    EditBox.Dock = DockStyle.Fill;
    EditBox.Enter += new EventHandler(EditBox_Refresh);
    EditBox.Leave += new EventHandler(EditBox_Refresh);
    EditBox.Resize += new EventHandler(EditBox_Refresh);
    this.Controls.Add(EditBox);
  }

  private void EditBox_Refresh(object sender, EventArgs e) {
    this.Invalidate();
  }

  protected override void OnPaint(PaintEventArgs e) {
    e.Graphics.Clear(SystemColors.Window);
    using (Pen borderPen = new Pen(this.EditBox.Focused ? _FocusBorderColor : _NormalBorderColor)) {
      e.Graphics.DrawRectangle(borderPen, new Rectangle(0, 0, this.ClientSize.Width - 1, this.ClientSize.Height - 1));
    }
    base.OnPaint(e);
  }
}

Upvotes: 5

Balazs Tihanyi
Balazs Tihanyi

Reputation: 6719

This is an ultimate solution to set the border color of a TextBox:

public class BorderedTextBox : UserControl
{
    TextBox textBox;

    public BorderedTextBox()
    {
        textBox = new TextBox()
        {
            BorderStyle = BorderStyle.FixedSingle,
            Location = new Point(-1, -1),
            Anchor = AnchorStyles.Top | AnchorStyles.Bottom |
                     AnchorStyles.Left | AnchorStyles.Right
        };
        Control container = new ContainerControl()
        {
            Dock = DockStyle.Fill,
            Padding = new Padding(-1)
        };
        container.Controls.Add(textBox);
        this.Controls.Add(container);

        DefaultBorderColor = SystemColors.ControlDark;
        FocusedBorderColor = Color.Red;
        BackColor = DefaultBorderColor;
        Padding = new Padding(1);
        Size = textBox.Size;
    }

    public Color DefaultBorderColor { get; set; }
    public Color FocusedBorderColor { get; set; }

    public override string Text
    {
        get { return textBox.Text; }
        set { textBox.Text = value; }
    }

    protected override void OnEnter(EventArgs e)
    {
        BackColor = FocusedBorderColor;
        base.OnEnter(e);
    }

    protected override void OnLeave(EventArgs e)
    {
        BackColor = DefaultBorderColor;
        base.OnLeave(e);
    }

    protected override void SetBoundsCore(int x, int y,
        int width, int height, BoundsSpecified specified)
    {
        base.SetBoundsCore(x, y, width, textBox.PreferredHeight, specified);
    }
}

Upvotes: 11

Related Questions