65.9K
CodeProject is changing. Read more.
Home

Richer RichTextBox (Part 2)

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.11/5 (9 votes)

Nov 9, 2005

viewsIcon

99637

downloadIcon

3410

An article on extending the RichTextBox class in C#.

Sample Image

Introduction

In the first part, we extended the RichTextBox class with methods that change the FontStyle of a selection without losing the styles that are currently present. Unfortunately, there are a few more features missing from the RichTextBox control that could potentially be useful in word-processor-like applications. These kinds of applications commonly use a status bar to display information about the current cursor position. In this part, we will enrich the RichTextBox control with functionality that can be used for that purpose.

Usage

When nothing is selected, we want to display line number, column number and cursor position. When some portion of text is selected, the status bar should display the start, end and length of the selection. Also, from the client perspective, those features should be self-documentary and easy to use.

this.rtb.CursorPositionChanged += 
    new System.EventHandler(this.rtb_CursorPositionChanged);
this.rtb.SelectionChanged += 
    new System.EventHandler(this.rtb_SelectionChanged);
.
.
.
private void rtb_CursorPositionChanged(object sender, System.EventArgs e)
{
    int line = rtb.CurrentLine;
    int col = rtb.CurrentColumn;
    int pos = rtb.CurrentPosition;
    
    statusBar.Text = "Line " + line + ", Col " + col + 
                     ", Position " + pos;
}

private void rtb_SelectionChanged(object sender, System.EventArgs e)
{
    int start = rtb.SelectionStart;
    int end = rtb.SelectionEnd;
    int length = rtb.SelectionLength;
    
    statusBar.Text = "Start " + start + ", End " + end + 
                     ", Length " + length;
}

To achieve such behavior, we need to extend the RichTextBox class in the following manner:

using System;
using System.Drawing;
using System.Windows.Forms;

namespace Nik.UserControls
{
    public class RicherTextBox2 : System.Windows.Forms.RichTextBox
    {
        public event EventHandler CursorPositionChanged;
        
        protected virtual void OnCursorPositionChanged( EventArgs e )
        {
            if ( CursorPositionChanged != null )
                CursorPositionChanged( this, e );
        }

        protected override void OnSelectionChanged( EventArgs e )
        {
            if ( SelectionLength == 0 )
                OnCursorPositionChanged( e );
            else
                base.OnSelectionChanged( e );
        }
            
        public int CurrentColumn
        {
            get { return CursorPosition.Column( this, SelectionStart ); }
        }

        public int CurrentLine
        {
            get { return CursorPosition.Line( this, SelectionStart ); }
        }

        public int CurrentPosition
        {
            get { return this.SelectionStart; }
        }

        public int SelectionEnd
        {
            get { return SelectionStart + SelectionLength; }
        }
    }
    
    internal class CursorPosition
    {
        [System.Runtime.InteropServices.DllImport("user32")] 
        public static extern int GetCaretPos(ref Point lpPoint);

        private static int GetCorrection(RichTextBox e, int index)
        {
            Point pt1 = Point.Empty;
            GetCaretPos(ref pt1);
            Point pt2 = e.GetPositionFromCharIndex(index);

            if ( pt1 != pt2 )
                return 1;
            else
                return 0;
        }

        public static int Line( RichTextBox e, int index )
        {
             int correction = GetCorrection( e, index );
             return e.GetLineFromCharIndex( index ) - correction + 1;
        }

        public static int Column( RichTextBox e, int index1 )
        {
             int correction = GetCorrection( e, index1 );
             Point p = e.GetPositionFromCharIndex( index1 - correction );

             if ( p.X == 1 )
                 return 1;

             p.X = 0;
             int index2 = e.GetCharIndexFromPosition( p );

             int col = index1 - index2 + 1;

             return col;
         }
    }
}

Resources