David's .net tales

Tuesday, April 05, 2005

Extending RichTextBox

RichTextBox inside .net winforms is a useful component, however it does not allow you to control and change some aspects of it. One thing it fails to allow you to do is get access to the scroll bars and change their values, it also doesn't let you control or set the underline style for the various items. All of these are actually possible, just not able to be done.

In .net 1.1 (although this should be fixed in .net 2.0 beta 2) the VScroll event is not fired when someone clicks and drags the thumbnail thingy on the scroll bar up and down, only when you click on the up and down arrows. This is extremely annoying if you are wanting to do things when the RichTextBox scrolls. I have included here my cobbled together RichTextBox which does a bunch of these things. I have taken some of this code from other blog sites, and some of it I wrote myself.

So this RichTextBox implements these extensions:

  • Printing
  • Appending RTF directly
  • Scroll bar messages when the thumb is moved
  • Underline colour and style changes
  • Accessing the scroll bar information
  • BeginUpdate/EndUpdate calls (I believe these exist in 2.0 now)
  • Code to run an application based on a clicked link in the RichTextBox

Explanation of how all the bits actually work

Over the next few days I will post explanations of how each bit works. To start with I will talk about how to catch the events so you can see when the Thumb position moves on the scroll bars.

Scroll events for the thumb

To get the scroll events for moving the thumb in the scroll bar, we override the WndProc function on the RichTextBox, this is the main procedure that is used to process all of the incoming windows messages. The two messages of WM_VSCROLL and WM_HSCROLL are sent when the thumb is moved, we check the bottom 16 bits of the WParam to see if it is set to SB_THUMTRACK or SB_THUMBPOSITION, if it is, then we fire the event. It is very important to call base.WndProc() in this procedure, or your control will not respond to anything at all any more.

This should work in .net framework v2.0 beta2 and onwards correctly, or at least it should according to the bug I filed. So you will not need to do this in newer versions of the framework, however this is a useful demonstration of how to override the things inside RichTextBox.

To find the details of the messages and how to use them, msdn is quite useful. The links to details of the WM_HSCROLL and WM_VSCROLL event is available on msdn.

To find the actual numbers to use for these events inside your c# code, you need to search using google or look inside your your visual studio code to find the includes for windows. Inside this header file you can find the #define that is used for the WM_VSCROLL and all the other associated things, like SB_ENDSCROLL. You then define all of these as constants inside c# and use them when referencing the specific messages.

protected override void WndProc(ref Message m)
{
    switch (m.Msg)
    {
        case WM_VSCROLL:
        base.WndProc(ref m);
        if ((m.WParam.ToInt32() & 0xffff) == SB_THUMBTRACK)
        {
            OnVScroll(EventArgs.Empty);
        }
        if ((m.WParam.ToInt32() & 0xffff) == SB_THUMBPOSITION)
        {
            OnVScroll(EventArgs.Empty);
        }
        break;

    case WM_HSCROLL:
        base.WndProc(ref m);
        if ((m.WParam.ToInt32() & 0xffff) == SB_THUMBTRACK)
        {
            OnHScroll(EventArgs.Empty);
        }
        if ((m.WParam.ToInt32() & 0xffff) == SB_THUMBPOSITION)
        {
            OnHScroll(EventArgs.Empty);
        }
        break;
    default:
        base.WndProc(ref m);
        break;
    }
}

Here is the actual code for the ExtendedRichTextBox

Here is the code for the ScrollBarInformation