Dutton

RichTextBox ScrollToCaret() bug

I recently needed to add selective colour to text in a Windows Forms TextBox. TextBox doesn't support this, but its close sibling RichTextBox does and as they both derive from TextBoxBase, the conversion in code was painless.

The original TextBox control would automatically set the caret (cursor) position to the end of the text and use ScrollToCaret() to ensure the last line was always visible after dynamically adding content. This doesn't quite work the same when called on a RichTextBox as it appears to scroll until just the very top of the caret is visible, resulting in at best a few pixels of the last line's text visible.

Quite a bit of googling of the problem reveals lots of discussion but not much in the way of a suggested solution.

Fortunately, user32.dll provides calls we can use to set the scroll position and we can access these unmanaged functions through P/Invoke as follows:

[StructLayout(LayoutKind.Sequential)]
public class POINT
{
    public int x;
    public int y;

    public POINT()
    {
    }

    public POINT(int x, int y)
    {
        this.x = x;
        this.y = y;
    }
}

const int SB_VERT = 1;
const int EM_SETSCROLLPOS = 0x0400 + 222;

[DllImport("user32", CharSet = CharSet.Auto)]
static extern bool GetScrollRange(IntPtr hWnd, int nBar, out int lpMinPos, out int lpMaxPos);

[DllImport("user32", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, int msg, int wParam, POINT lParam)

Then, when you want to set the scroll position ("control" is your RichTextBox instance):

int min, max;
GetScrollRange(control.Handle, SB_VERT, out min, out max);
SendMessage(control.Handle, EM_SETSCROLLPOS, 0, new POINT(0, max - control.Height));

Share this: