RichTextBox syntax highlighting in real time--Disabling the repaint

Robz picture Robz · Jul 19, 2010 · Viewed 9.2k times · Source

I'm creating a function that takes a RichTextBox and has access to a list of keywords & 'badwords'. I need to highlight any keywords & badwords I find in the RichTextBox while the user is typing, which means the function is called every time an editing key is released.

I've written this function, but the words and cursor in the box flicker too much for comfort.

I've discovered a solution--to disable the RichTextBox's ability to repaint itself while I'm editing and formatting its text. However, the only way I know to do this is to override the "WndProc" function and intercept (what I've been about to gather is) the repaint message as follows:

protected override void WndProc(ref System.Windows.Forms.Message m)
{
    if (m.Msg == 0x00f) {
         if (paint)
            base.WndProc(ref m);
         else
            m.Result = IntPtr.Zero;
    }
    else
         base.WndProc(ref m);
}

Where the boolean 'paint' is set to false just before I start highlighting and to true when I finish. But as I said, the function I make must take in a RichTextBox; I cannot use a subclass.

So, is there a way to disable the automatic repainting of a RichTextBox 'from the outside?'

Answer

Hans Passant picture Hans Passant · Jul 19, 2010

It is an oversight in the RichTextBox class. Other controls, like ListBox, support the BeginUpdate and EndUpdate methods to suppress painting. Those methods generate the WM_SETREDRAW message. RTB in fact supports this message, but they forgot to add the methods.

Just add them yourself. Project + Add Class, paste the code shown below. Compile and drop the control from the top of the toolbox onto your form.

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;

class MyRichTextBox : RichTextBox {
    public void BeginUpdate() {
        SendMessage(this.Handle, WM_SETREDRAW, (IntPtr)0, IntPtr.Zero);
    }
    public void EndUpdate() {
        SendMessage(this.Handle, WM_SETREDRAW, (IntPtr)1, IntPtr.Zero); 
        this.Invalidate();
    }
    [DllImport("user32.dll")]
    private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);
    private const int WM_SETREDRAW = 0x0b;
}

Or P/Invoke SendMessage directly before/after you update the text.