Textbox border issue c#

OmkarHcl 206 Reputation points
2023-06-08T09:01:28.2466667+00:00

Below is the code by which I am trying to create a custom textbox who should have double underline in its bottom border , single border on up side and no borders on left and right side but it is not working as i am not getting top border . also there are something in its left and right border . . Also i am getting flickering problem on the top side of the control . Please suggest what modification should i have to make in my code Or please suggest new code block

 public partial class doubleunderlinetextbox : TextBox
    {
        public doubleunderlinetextbox()
        {
            // InitializeComponent();
            //BorderStyle = BorderStyle.None;
            BorderStyle = System.Windows.Forms.BorderStyle.None;
            AutoSize = false; //Allows you to change height to have bottom padding
            Controls.Add(new Label()
            { Height = 1, Dock = DockStyle.Bottom, BackColor = Color.Black });
        }

   [DllImport("user32")]
        private static extern IntPtr GetWindowDC(IntPtr hwnd);
        struct RECT
        {
            public int left, top, right, bottom;
        }
        struct NCCALSIZE_PARAMS
        {
            public RECT newWindow;
            public RECT oldWindow;
            public RECT clientWindow;
            IntPtr windowPos;
        }

        float clientPadding = 0;
        int actualBorderWidth = 2;
        Color borderColor = Color.Black;
        protected override void WndProc(ref Message m)
        {
            //We have to change the clientsize to make room for borders
            //if not, the border is limited in how thick it is.
            if (m.Msg == 0x83)
            { //WM_NCCALCSIZE 
                if (m.WParam == IntPtr.Zero)
                {
                    RECT rect = (RECT)Marshal.PtrToStructure(m.LParam, typeof(RECT));
                    rect.left += 2;
                    rect.right -= 2;
                    rect.top -= 0;
                    rect.bottom -= 0;// (int)clientPadding;
                    Marshal.StructureToPtr(rect, m.LParam, false);
                }
                else
                {
                    NCCALSIZE_PARAMS rects = (NCCALSIZE_PARAMS)Marshal.PtrToStructure(m.LParam, typeof(NCCALSIZE_PARAMS));
                    rects.newWindow.left += (int)clientPadding;
                    rects.newWindow.right -= (int)clientPadding;
                    rects.newWindow.top -=2 ;
                    rects.newWindow.bottom -= 2;
                    Marshal.StructureToPtr(rects, m.LParam, false);
                }
            }
            if (m.Msg == 0x85)
            {//WM_NCPAINT    
                IntPtr wDC = GetWindowDC(Handle);
                using (Graphics g = Graphics.FromHdc(wDC))
                {
                    ControlPaint.DrawBorder(g, new Rectangle(0, 0, Size.Width, Size.Height),
                        Color.Transparent, 1, ButtonBorderStyle.Solid,
                        borderColor, actualBorderWidth, ButtonBorderStyle.Solid,
                        Color.Transparent, 1, ButtonBorderStyle.Solid,
                        borderColor, actualBorderWidth, ButtonBorderStyle.Solid);
                }
                return;
            }
            base.WndProc(ref m);
        }

this is what i am getting
textboxerror

This is what I am trying to get

enter image description here

Developer technologies Windows Forms
Developer technologies C#
0 comments No comments
{count} votes

2 answers

Sort by: Most helpful
  1. Hui Liu-MSFT 48,676 Reputation points Microsoft External Staff
    2023-06-09T06:16:14.11+00:00

    Hi,@OmkarHcl. You could use the following code to accomplish it.

    Codebedhind:

      doubleunderlinetextbox tb = new doubleunderlinetextbox();
                tb.Location = new Point(51, 257);
                tb.Size = new Size(212, 100);
               
                tb.Text = "hello";
                this.Controls.Add(tb);
    

    doubleunderlinetextbox:

      public class doubleunderlinetextbox : TextBox
        {
    
            public doubleunderlinetextbox()
            {
                AutoSize = false;
                BorderStyle = BorderStyle.None;
                
                SetStyle(ControlStyles.UserPaint, true);
                SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            }
    
    
            protected override void OnPaint(PaintEventArgs e)
            {
    
                base.OnPaint(e);
    
                Rectangle borderRect = new Rectangle(0, 0, Width, Height);
    
    
                using (Pen topBorderPen = new Pen(BorderColor, 2))
                {
                    e.Graphics.DrawLine(topBorderPen, borderRect.Left, borderRect.Top + 1, borderRect.Right, borderRect.Top + 1);
                }
                using (Pen underlineBorderPen = new Pen(BorderColor, 2))
                {
                    e.Graphics.DrawLine(underlineBorderPen, borderRect.Left, borderRect.Bottom - 6, borderRect.Right, borderRect.Bottom - 6);
    
                }
                using (Pen underlineBorderPen = new Pen(BorderColor, 6))
                {
                    e.Graphics.DrawLine(underlineBorderPen, borderRect.Left, borderRect.Bottom, borderRect.Right, borderRect.Bottom);
                }
                if (!string.IsNullOrEmpty(Text))
                {
                    TextRenderer.DrawText(e.Graphics, Text, Font, borderRect, ForeColor, TextFormatFlags.VerticalCenter | TextFormatFlags.HorizontalCenter);
                }
            }
    
            private Color borderColor = Color.Black;
    
            public Color BorderColor
            {
                get { return borderColor; }
                set
                {
                    borderColor = value;
                    Invalidate();
                }
            }
            
    
        }
    

    The result:

    User's image

    Update: I updated the code as follows, it will block part of the top line when entering text.

     public class doubleunderlinetextbox : TextBox
        {
    
    
            private Rectangle outerRect;
            private Rectangle innerRect;
    
            public doubleunderlinetextbox()
            {
                SetStyle(ControlStyles.UserPaint, true);
                SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
                AutoSize = false;
    
                Multiline = true;
                int padding = 8;
                outerRect = new Rectangle(0, 0, Width, Height);
    
                innerRect = new Rectangle(outerRect.Left + padding, outerRect.Top + padding, outerRect.Width - padding * 2, outerRect.Height - padding * 3);
    
                TextChanged += CustomTextBox_TextChanged;
            }
    
            protected override void OnPaint(PaintEventArgs e)
            {
                base.OnPaint(e);
    
                using (Pen topBorderPen = new Pen(BorderColor, 4))
                {
                    e.Graphics.DrawLine(topBorderPen, outerRect.Left, outerRect.Top, outerRect.Right, outerRect.Top);
                }
                using (Pen underlineBorderPen = new Pen(BorderColor, 2))
                {
                    e.Graphics.DrawLine(underlineBorderPen, outerRect.Left, outerRect.Bottom-10, outerRect.Right, outerRect.Bottom-10);
                }
                using (Pen underlineBorderPen = new Pen(BorderColor, 4))
                {
                    e.Graphics.DrawLine(underlineBorderPen, outerRect.Left, outerRect.Bottom -6 , outerRect.Right, outerRect.Bottom -6);
                }
    
                using (Pen innerPen = new Pen(InnerBorderColor, 0))
                {
                    e.Graphics.DrawRectangle(innerPen, innerRect);
                }
    
                using (SolidBrush textBrush = new SolidBrush(ForeColor))
                {
                    StringFormat format = new StringFormat();
                   
                    e.Graphics.DrawString(Text, Font, textBrush, innerRect, format);
                }
            }
    
            protected override void OnSizeChanged(EventArgs e)
            {
                base.OnSizeChanged(e);
    
                int padding = 8;
                outerRect = new Rectangle(0, 0, Width, Height);
                innerRect = new Rectangle(outerRect.Left + padding, outerRect.Top + padding, outerRect.Width - padding * 2, outerRect.Height - padding * 2);
            }
    
            private Color borderColor = Color.Black;
    
            public Color BorderColor
            {
                get { return borderColor; }
                set
                {
                    borderColor = value;
                    Invalidate();
                }
            }
    
            private Color innerBorderColor = Color.Transparent;
    
            public Color InnerBorderColor
            {
                get { return innerBorderColor; }
                set
                {
                    innerBorderColor = value;
                    Invalidate();
                }
            }
    
            protected override void WndProc(ref Message m)
            {
                const int WM_CHAR = 0x0102;
                const int WM_PASTE = 0x0302;
                const int WM_CLEAR = 0x0303;
                const int WM_CUT = 0x0300;
                const int WM_KEYDOWN = 0x0100;
    
                switch (m.Msg)
                {
                    case WM_CHAR:
                    case WM_PASTE:
                    case WM_CLEAR:
                    case WM_CUT:
                        if (!innerRect.Contains(PointToClient(Cursor.Position)))
                            return;
                        break;
                    case WM_KEYDOWN:
                        if (((Keys)m.WParam) == Keys.Left || ((Keys)m.WParam) == Keys.Right)
                            return;
                        break;
                }
    
                base.WndProc(ref m);
            }
    
            private void CustomTextBox_TextChanged(object sender, System.EventArgs e)
            {
                //  Restrict text within the inner rectangle
                if (!innerRect.Contains(PointToClient(Cursor.Position)))
                {
                    if (SelectionStart <= innerRect.Left) 
                    {
                        SelectionStart = innerRect.Left ;
    
                    }
                       
                    else if (SelectionStart >= innerRect.Right)
                        SelectionStart = innerRect.Right - 1;
    
                    Text = Text.Substring(0, innerRect.Left) + Text.Substring(innerRect.Right);
                    SelectionStart = innerRect.Left;
                }
            }
    
            
        }
    
    

    The result:


    If the response is helpful, please click "Accept Answer" and upvote it.

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


  2. Castorix31 90,521 Reputation points
    2023-06-09T10:04:31.0766667+00:00

    You can use EM_SETRECT to draw outside the text

    Something like this :

        public partial class CustomTextBox : RichTextBox
        {
            [DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
            public static extern int SendMessage(IntPtr hWnd, uint msg, IntPtr wParam, ref RECT lParam);
    
            [StructLayout(LayoutKind.Sequential)]
            public struct RECT
            {
                public int left;
                public int top;
                public int right;
                public int bottom;
                public RECT(int Left, int Top, int Right, int Bottom)
                {
                    left = Left;
                    top = Top;
                    right = Right;
                    bottom = Bottom;
                }
            }
    
            public const int EM_SETRECT = 0x00B3;
    
            public const int WM_PAINT = 0x000F;
    
            public CustomTextBox()
            {
                //InitializeComponent();
                BorderStyle = System.Windows.Forms.BorderStyle.None;
                SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
                AutoSize = false;
                this.ScrollBars = System.Windows.Forms.RichTextBoxScrollBars.None;
                RECT rc = new RECT(this.ClientRectangle.Left, this.ClientRectangle.Top + 10, this.ClientRectangle.Right, this.ClientRectangle.Bottom - 10);
                SendMessage(this.Handle, EM_SETRECT, IntPtr.Zero, ref rc);
            }
    
            protected override void WndProc(ref Message m)
            {
                base.WndProc(ref m);
                switch (m.Msg)
                {
                    case WM_PAINT:
                        PaintEventArgs pe = new PaintEventArgs(this.CreateGraphics(), this.RectangleToScreen(this.ClientRectangle));
                        this.OnPaint(pe);
                        break;
                }
            }
    
            protected override void OnPaint(PaintEventArgs pe)
            {
                using (Pen penTop = new Pen(BorderColor, 2))
                {
                    pe.Graphics.DrawLine(penTop, 0, 2, this.ClientRectangle.Right, 2);
                }
                using (Pen penBottom1 = new Pen(BorderColor, 2))
                {
                   pe.Graphics.DrawLine(penBottom1, 0, this.ClientRectangle.Bottom - 5, this.ClientRectangle.Right, this.ClientRectangle.Bottom - 5);
                }
                using (Pen penBottom2 = new Pen(BorderColor, 2))
                {
                    pe.Graphics.DrawLine(penBottom2, 0, this.ClientRectangle.Bottom - 2, this.ClientRectangle.Right, this.ClientRectangle.Bottom - 2);
                }
            }
    
            private Color borderColor = Color.Black;
    
            public Color BorderColor
            {
                get { return borderColor; }
                set
                {
                    borderColor = value;
                    Invalidate();
                }
            }
        }
    

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.