§ April 20, 2004

ScrollableRichTextBox

The standard RichTextBox's "Auto-Scroll" functionality is so obscure, that most rarely ever find out how to use it. This class appends text and gives the option for the user to scroll to the bottom of the textbox.
/******************************************************/
/*          NULLFX FREE SOFTWARE LICENSE              */
/******************************************************/
/*  ScrollableRichTextBox Library                     */
/*  by: Steve Whitley                                 */
/*  © 2005 NullFX Software                            */
/*                                                    */
/* NULLFX SOFTWARE DISCLAIMS ALL WARRANTIES,          */
/* RESPONSIBILITIES, AND LIABILITIES ASSOCIATED WITH  */
/* USE OF THIS CODE IN ANY WAY, SHAPE, OR FORM        */
/* REGARDLESS HOW IMPLICIT, EXPLICIT, OR OBSCURE IT   */
/* IS. IF THERE IS ANYTHING QUESTIONABLE WITH REGARDS */
/* TO THIS SOFTWARE BREAKING AND YOU GAIN A LOSS OF   */
/* ANY NATURE, WE ARE NOT THE RESPONSIBLE PARTY. USE  */
/* OF THIS SOFTWARE CREATES ACCEPTANCE OF THESE TERMS */
/*                                                    */
/* USE OF THIS CODE MUST RETAIN ALL COPYRIGHT NOTICES */
/* AND LICENSES (MEANING THIS TEXT).                  */
/*                                                    */
/******************************************************/

namespace NullFX.Controls {
    using System;
    using System.Windows.Forms;
    /// <summary>
    /// This components adds a much lacking function
    /// "Scroll to the end" which is missing
    /// from the original rich text box.
    /// </summary>
    public class ScrollableRichTextBox : RichTextBox {
        // constants for the message sending
        const int WM_VSCROLL = 0x0115;
        const int WM_LBUTTONDOWN = 0x0201;
        const int WM_SETFOCUS = 0x0007;
        const int WM_KILLFOCUS = 0x0008;
        readonly IntPtr SB_ENDSCROLL = (IntPtr)8;
        readonly IntPtr SB_BOTTOM = (IntPtr)7;
        // flag we use to determine if we can scroll
        bool _scrollable = true;
        private delegate void AppendTextDelegate(string text, bool scrollToEnd);
        public void AppendText(string text, bool scrollToEnd) {
            if(InvokeRequired) {
                Invoke(new AppendTextDelegate(AppendText), 
                           new object[] {text, scrollToEnd});
            }else {
                decimal length = base.Text.Length + text.Length;
                if(length >= base.MaxLength) base.Clear();
                base.Text += text;
                if(_scrollable && scrollToEnd) {
                    if(IntPtr.Zero != base.Handle) {
                        base.SelectionStart = base.Text.Length;
                        Message m = Message.Create(
                            base.Handle, 
                            WM_VSCROLL, 
                            SB_BOTTOM, IntPtr.Zero);
                        base.WndProc(ref m);
                    }
                }
            }

        }

        protected override void WndProc(ref Message m) {
            // if we're in a scroll set the scrolling flag 
            // to false & skip theauto scroll
            if((m.Msg == WM_LBUTTONDOWN) 
                || m.Msg == WM_VSCROLL 
                && m.WParam != SB_BOTTOM) {
                _scrollable = false;
            }

            // if we are done scrolling, set the falg to true & do the scrolling
            if(m.Msg == WM_VSCROLL && m.WParam == SB_ENDSCROLL) {
                _scrollable = true;
            }
            // HACK: this keeps the user from setting the cursor in the textbox
            //  because that causes problems if they do
            if(m.Msg == WM_SETFOCUS && base.ReadOnly) m.Msg = WM_KILLFOCUS;

            base.WndProc (ref m);
        }
    }
}

There used to be a threading problem which would throw an unhandled exception every now and then, but due to an article recently published on msdn blogs this has been fixed, and the change is reflected above.


Posted 21 years, 7 months ago on April 20, 2004

Comments have now been turned off for this post

© 2003 - 2024 NullFX
Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License