Implementing a scrolling RichTextBox
It is often necessary to make a .NET RichTextBox scroll to the top or the bottom. Unfotunately there is no direct method of doing this in the class itself.
One possible solution involves using the ScrollToCaret() function of the control. This method is outlined in my first post about RichTextBox scrolling. It appears that some programmers have had problems with that solution though. It requires careful management of focus in the application to work under all circumstances.
The ScrollingRichTextBox
A far more elegant solution is to use the underlying message system to control the scroll. Using the SendMessage function it is possible to send a WM_VSCROLL message to the control that makes the control scroll without needing to worry about focus.
I think the best solution is to make a small class that inherits from RichTextBox, and neatly wraps the SendMessage calls necessary to make it work. Many programmers are unfamiliar with the syntax involved, so wrapping it in a more familiar syntax is a good idea.
The complete class looks like this:
class ScrollingRichTextBox : System.Windows.Forms.RichTextBox { [DllImport("user32.dll", CharSet = CharSet.Auto)] private static extern IntPtr SendMessage( IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam); private const int WM_VSCROLL = 277; private const int SB_LINEUP = 0; private const int SB_LINEDOWN = 1; private const int SB_TOP = 6; private const int SB_BOTTOM = 7; public void ScrollToBottom() { SendMessage(Handle, WM_VSCROLL, new IntPtr(SB_BOTTOM), new IntPtr(0)); } public void ScrollToTop() { SendMessage(Handle, WM_VSCROLL, new IntPtr(SB_TOP), new IntPtr(0)); } public void ScrollLineDown() { SendMessage(Handle, WM_VSCROLL, new IntPtr(SB_LINEDOWN), new IntPtr(0)); } public void ScrollLineUp() { SendMessage(Handle, WM_VSCROLL, new IntPtr(SB_LINEUP), new IntPtr(0)); } }
Feel free to steal…
How it works
The class imports the SendMessage function from the user32.dll system library. I’m not gonna go deeply into that function in this post. It is insanely powerfull and deserves it’s own post someday. It allows the program to send native windows messages to the control. The message in play here is the WM_VSCROLL message that takes a parameter that tells it how to scroll. These parameters are constants that are defined in the winuser.h header file.
I have implemented four functions in this class, allowing it to scroll to the top and bottom, as well as a single line up and down.
With the SendMessage function imported and using winuser.h as a reference you could easily implement even more functionality in the class, such as pageup/pagedown (SB_PAGEUP/SB_PAGEDOWN), but i don’t want to bloat the class with that for this article. The principle is what counts here.
A simple usage example
For applications that require this sort of scrolling, using the ScrollingRichTextBox over the ordinary RichTextBox is the way to go. In a previous blog post, i talked about hooking up to the OnTextChanged event of a RichTextBox and using ScrollToCaret() to do the scrolling. A method that has a few issues.
Now, using the ScrollingRichTextBox, these issues are resolved and the complete code for that event looks like this:
private void scrollingRichTextBox_TextChanged(object sender, EventArgs e) { scrollingRichTextBox.ScrollToBottom(); }
Neat huh?

June 6th, 2009 at 5:37 pm
This code is very useful, i had no problems with my scrolling crap, but some people do not know how to use this so please explain better.
June 22nd, 2009 at 6:31 am
Jeez how much clearer could he have made it…
June 30th, 2009 at 7:19 am
How this can be done in silverlight, i am having a web application developed in silverlight and i am using the third party control RichTextBox in my application, how can i implement the scrolling feature for RichTextBox, i included the third party control DLL in my appli
June 30th, 2009 at 8:24 am
I don’t know anything about Silverlight, sorry….
October 19th, 2009 at 1:58 am
I’m a little late, but thanks for this brilliant bit of code. I’ve turned it into an Extension method, which makes it automatically usable in on any TextBoxBase class without any pesky inheritance.
[code]
using System;
using System.Runtime.InteropServices;
namespace Extensions
{
public static class UIExtensions
{
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr SendMessage(
IntPtr hWnd,
uint Msg,
IntPtr wParam,
IntPtr lParam);
private const int WM_VSCROLL = 277;
private const int SB_LINEUP = 0;
private const int SB_LINEDOWN = 1;
private const int SB_TOP = 6;
private const int SB_BOTTOM = 7;
public static void ScrollToBottom(this System.Windows.Forms.TextBoxBase tb)
{
SendMessage(tb.Handle, WM_VSCROLL, new IntPtr(SB_BOTTOM), new IntPtr(0));
}
public static void ScrollToTop(this System.Windows.Forms.TextBoxBase tb)
{
SendMessage(tb.Handle, WM_VSCROLL, new IntPtr(SB_TOP), new IntPtr(0));
}
public static void ScrollLineDown(this System.Windows.Forms.TextBoxBase tb)
{
SendMessage(tb.Handle, WM_VSCROLL, new IntPtr(SB_LINEDOWN), new IntPtr(0));
}
public static void ScrollLineUp(this System.Windows.Forms.TextBoxBase tb)
{
SendMessage(tb.Handle, WM_VSCROLL, new IntPtr(SB_LINEUP), new IntPtr(0));
}
}
}
[/code]
Usage is exactly the same:
[code]
private void anyTextBox_TextChanged(object sender, EventArgs e)
{
textLogMain.ScrollToBottom();
}
[/code]
October 19th, 2009 at 1:59 am
Apologies, I don’t know how to format code in comments, I assumed [code][/code].
Also the usage method should be:
private void anyTextBox_TextChanged(object sender, EventArgs e)
{
anyTextBox.ScrollToBottom();
}
October 19th, 2009 at 7:47 am
That’s brilliant Yamen, Thanks.
October 20th, 2009 at 8:00 pm
Holy cow, thanks, this is great! And thanks to Yamen as well for repackaging the solution
December 7th, 2009 at 9:11 pm
Hi Jakob and Yamen,
Most other solutions on the web for this problem say to use the ScrolLToCarret() method. This method had two problems for me:
1) The scrollbar of the RichTextBox would flicker (jump up and then down) whenever I called ScrolLToCarret().
2) The RichTextBox would never scroll *all the way* down. It would always stop a few pixels above the bottom (so annoying!).
Your solution solves both of these problems and makes my work look a bit more professional
. Kudos to you and many thanks.
- Harvo
April 14th, 2010 at 4:21 pm
I love the solution. How can you determine if you have scrolled all the way to the bottom?
February 6th, 2012 at 1:36 pm
WoW….
I have been developing a C# program to communicate with an amateur radio modem (PK-232) via a serial port and struggled with the rich text box scrolling issue until I found this very elegant solution.
I can not believe that this is not part of the rich text box class…
Thank you VERY much….
DenS