1

I'm trying to create a custom RichTextBox with border color, but i have a problem... My border color not showing

Here's my code :

public partial class AlXRichTextBox : RichTextBox
{
    private RichTextBox textBox;

    private Color borderColor;

    public AlXRichTextBox()
    {
        InitializeComponent();
    }
    public Color BorderColor
    {
        get { return borderColor; }
        set { borderColor = value; Invalidate(); }
    }
    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);

        Pen p = new Pen(borderColor);
        Graphics g = e.Graphics;
        int variance = 3;
        //g.DrawRectangle(p, new Rectangle(base.Location.X - variance, base.Location.Y - variance, base.Width + variance, base.Height + variance));
        ControlPaint.DrawBorder(e.Graphics, base.ClientRectangle, borderColor, ButtonBorderStyle.Solid);
    }

    private void InitializeComponent()
    {
            this.textBox = new System.Windows.Forms.RichTextBox();
            this.SuspendLayout();
            // 
            // richTextBox1
            // 
            this.textBox.Location = new System.Drawing.Point(0, 0);
            this.textBox.Name = "richTextBox1";
            this.textBox.Size = new System.Drawing.Size(100, 96);
            this.textBox.TabIndex = 0;
            this.textBox.Text = "";
            this.textBox.Multiline = true;
            this.textBox.BorderStyle = BorderStyle.None;
            // 
            // AlXRichTextBox
            // 
            this.Size = new System.Drawing.Size(278, 123);
            this.ResumeLayout(false);
    }
}

What's problem with this ?

Tatranskymedved
  • 4,194
  • 3
  • 21
  • 47
Al00X
  • 1,492
  • 1
  • 12
  • 17

2 Answers2

2

Referring to MSDN article :

Overriding OnPaint will not allow you to modify the appearance of all controls. Those controls that have all of their painting done by Windows (for example, TextBox) never call their OnPaint method, and thus will never use the custom code. Refer to the Help documentation for the particular control you want to modify to see if the OnPaint method is available. For a list of all the Windows Form Controls, see Controls to Use on Windows Forms. If a control does not have OnPaint listed as a member method, you cannot alter its appearance by overriding this method. For more information about custom painting, see Custom Control Painting and Rendering.

However there is a "hack", You can achieve calling the Paint method by calling following code:

 private const int WM_PAINT = 15;
 protected override void WndProc(ref System.Windows.Forms.Message m)
 {
     base.WndProc(ref m);
     if (m.Msg == WM_PAINT && !inhibitPaint)
     {
         // raise the paint event
         using (Graphics graphic = base.CreateGraphics())
             OnPaint(new PaintEventArgs(graphic,
             base.ClientRectangle));
     }
  }

  private bool inhibitPaint = false;

  public bool InhibitPaint
  {
      set { inhibitPaint = value; }
  }

Src: RichTextBox and UserPaint

Other point is that You cannot draw outside of the Rectangle (which is total size of Your RichTB component. So You actually want to provide him with different Coords (smaller inner ones) and You will draw to the outside.

Your class will look like:

public partial class AlXRichTextBox : RichTextBox
{
    private Color borderColor = Color.Red;

    public Color BorderColor
    {
        get { return borderColor; }
        set { borderColor = value; Invalidate(); }
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        int variance = 3;
        e = new PaintEventArgs(e.Graphics, new Rectangle(e.ClipRectangle.X + variance, e.ClipRectangle.Y + variance, e.ClipRectangle.Width - variance, e.ClipRectangle.Height - variance));
        base.OnPaint(e);

        Pen p = new Pen(borderColor, variance);
        Graphics g = e.Graphics;
        g.DrawRectangle(p, new Rectangle(e.ClipRectangle.X, e.ClipRectangle.Y, e.ClipRectangle.Width, e.ClipRectangle.Height));
    }


    private const int WM_PAINT = 15;
    protected override void WndProc(ref System.Windows.Forms.Message m)
    {
        base.WndProc(ref m);
        if (m.Msg == WM_PAINT && !inhibitPaint)
        {
            // raise the paint event
            using (Graphics graphic = base.CreateGraphics())
                OnPaint(new PaintEventArgs(graphic,
                 base.ClientRectangle));
        }

    }

    private bool inhibitPaint = false;

    public bool InhibitPaint
    {
        set { inhibitPaint = value; }
    }
}

IMPORTANT

As it is not expected for this control to be changed by Paint, You will get "not nice" behavior in regards to the drawing changes like border, new elements etc.. If You would like to use such element, consider using WPF - Windows Presentation Foundation. They are much more nicer to templating the items and modifying design.

Community
  • 1
  • 1
Tatranskymedved
  • 4,194
  • 3
  • 21
  • 47
0

A little late answer, but I was on same path as you these days and It got me to this solution, It works for me:

using System;
using System.Drawing;
using System.Windows.Forms;

public class MyRichTextBox : RichTextBox
{
    private const UInt32 WM_PAINT = 0x000F;
    private const UInt32 WM_USER = 0x0400;
    private const UInt32 EM_SETBKGNDCOLOR = (WM_USER + 67);
    private const UInt32 WM_KILLFOCUS = 0x0008;

    public MyRichTextBox()
    {
        this.BorderStyle = System.Windows.Forms.BorderStyle.None;
    }

    protected override void WndProc(ref System.Windows.Forms.Message m)
    {
        base.WndProc(ref m);

        Graphics g = Graphics.FromHwnd(Handle);
        Rectangle bounds = new Rectangle(0, 0, Width - 1, Height - 1);
        Pen p = new Pen(SystemColors.Highlight, 3);

        if (m.Msg == WM_PAINT)
        {
            if (this.Enabled == true)
            {

                if (this.Focused)
                {
                    g.DrawRectangle(p, bounds);
                }

                else
                {
                    g.DrawRectangle(SystemPens.ControlDark, bounds);
                }

            }
            else
            {
                g.FillRectangle(Brushes.White, bounds);
                g.DrawRectangle(SystemPens.Control, bounds);
            }
        }

        if (m.Msg == EM_SETBKGNDCOLOR) //color disabled background
        {
            Invalidate();
        }

        if (m.Msg == WM_KILLFOCUS) //set border back to normal on lost focus
        {
            Invalidate();
        }
    }

}

This Rich Textbox changes 3 border colors - enabled, focused and disabled with disabled background. As you see the code is simple and short. The only trick is to overide KILL_FOCUS and EM_SETBKGNDCOLOR messages (this one is for changing disabled background), and RichTextbox should be BorderStyle=None. Cheers !

LuckyLuke82
  • 586
  • 1
  • 18
  • 58