Click here to Skip to main content
Click here to Skip to main content

Line Numbers for RichText Control in C#

By , 11 Aug 2009
 

Introduction

Please wait while more details are being updated.

This article is a converted project from VB.NET to C#, originally created by nogChoco in the article, "LineNumbers for the RichTextBox".

Sure anyone can make a line numbering user control.  I've made many variations of them for VB 3.0 to 6.0 & C++, always using picture boxes or whatever as a drawing base to mark the position. When Microsoft released the newer versions of RichText control boxes (in more recent versions), the old methods went out the door.  By this, I mean that one can easily zoom in & out of the box by holding down Ctrl (or Shift) key while using the mouse wheel, posing a HUGE problem for traditional methods. 

Q: Why use RichText instead of the traditional TextBox?
A: (In older versions) RichText can hold more data! (and offers more features)

LineNumbers.png

Before Compiling Fore-note  

I have successfully compiled & ran this example project under both Visual Studio 2008 & SharpDevelop 3.x using Framework 2.0.

You will probably have problems running this example project under VS 2005 & lower; do note the control does work under the Framework 2.0If you are having problems running this under VS 2005 or other studios, you might want to either find yourself a project converter or upgrade your studio. I am very sorry if this is an inconvenience for you, that is why this is posted for Intermediate & Expert users. 

If you want a free IDE that can run this, try out SharpDevelop IDE.

Compiling Your Own Project

LineNumbers_-_ex3.png

Using SharpDevelop (3.x) 

  1. Create a new C# Windows project
  2. Add Reference to your project (Right click 'References' > 'Add Reference')
  3. Under GAC Tab select: "Microsoft.VisualBasic"
  4. Insert into your project existing item.. "linenum_rtf.cs"
  5. Under Custom Components, insert "LineNumbers_For_RichTextBox" into your form as well as insert a RichTextBox
  6. Line them up side by side (left side by default)
  7. Link Line Numbers to your RichTextBox
    1. Under "Add LineNumbers to" > "Parent Rich Text Box":
    2. Select your RichTextBox to add line numbers to
    3. (feel free to customize it on your own)
  8. Run the project!

Using Visual Studio (2008)

  1. Create a new C# Windows Project
  2. Add Reference to your project (Right click 'References' > 'Add Reference')
  3. Under .NET Tab select: "Microsoft.VisualBasic"
  4. Insert the existing item into your project... "linenum_rtf.cs"
  5. Build your project!
    1. This will not show under Custom Components unless you build you the project first!
  6. Under Custom Components, insert "LineNumbers_For_RichTextBox" into your form as well as insert a RichTextBox
  7. Line them up side by side (left side by default)
  8. Link Line Numbers to your RichTextBox
    1. Under "Add LineNumbers to" > "Parent Rich Text Box":
    2. Select your RichTextBox to add line numbers to
    3. (feel free to customize it on your own)
  9. Run the project!

Background and Points of Interest

As a software designer/developer like all of you, time is of the essence when meeting deadlines! This example using the RichText control works great! Especially with the zoom in/out feature using the mouse wheel, and it added nice graphical features which can be easily customized. However, I feel the urging need to program in C# and this example was only provided in VB.NET... It was time to upgrade it & now, on with the show!

History

  • 2009.08.05 - Initial conversion from VB.NET to C#
  • 2009.08.08 - Updated notes on this page (pictures soon to come)

To Do

  • Provide 2 versions
    • Graphical: The current version (customizable and beautiful)
    • Simple: Side bar is simple & has low overhead on your projects
  • Strip out references to Microsoft.VisualBasic so it's more pure C#

- Damian J. Suess of Xeno Innovations, Inc. [2000-2009]

License

This article, along with any associated source code and files, is licensed under The Common Development and Distribution License (CDDL)

About the Author

Damian J. Suess
CEO Xeno Innovations, Inc.
United States United States
Member
[ Exceeding the Limits of Imagination ]

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
Questionline numbers disappear when the # of lines is large?memberCheeso31 Mar '10 - 13:23 
I noticed that the line numbers seemed to disappear when I displayed an RTB with hundreds of lines. ??
 
I looked in Update_SizeAndPosition() and found that the edge of the linenumbers control was being moved outwards, either left or right, depending on how it was docked to the parent RTB. When there were, say, 4 digits to display, and the linenumbers control was displayed on the left, the left edge of it would move further leftward. This became a problem when the control was anchored to the left edge of the form.
 
So I reworked the Update_SizeAndPosition() method, based on the principle that the bounding box of the linenumebers control plus its parent should not change, regardless of how wide the digits display could become. In other words, when docked to the left of the RTB, the left edge of the linenumbers control should never move further leftward, and the right edge of the RTB should never move further rightward.
 
Conversely, when docked to the right edge of the RTB, the right edge of the linenumbers control should nevevr move further rightward, and the left edge of the RTB should never move further leftward. If that makes sense.
 
The only movement, then, should be on the internal borderline, between the two controls. As the linenumbers control needs to expand, the RTB should shrink, horizontally.
 
The modified code looks like this:
 
else if (zDockSide != LineNumberDockSide.None)
{
    // --- DockSide is active L/R/H

    // line up the tops of the numbers and the RTB
    zNewLocation.Y = zParent.Top;
    zNewSize.Height = zParent.Height;
 
    // Principle: keep the overall size of the RTB and
    // the RtbLineNumbers, the same.
    // --------------------------------------------
    // The left edge of the RtbLineNumbers must remain
    // fixed when it is displayed to the left.  The
    // right edge of the RtbLineNumbers when it is
    // displayed to the right.
    // --------------------------------------------
    //
    // Corollary: only move the border between the two.

    if (zAutoSizing_Size.Width > 0)
        zNewSize.Width = zAutoSizing_Size.Width;
 
    int delta = zNewSize.Width - this.Size.Width;
 
    if (delta == 0) return; // no change!

 
    var newParentSize = zParent.Size;
    newParentSize.Width = newParentSize.Width - delta;
 
    if (zDockSide == LineNumberDockSide.Left)
    {
        // The line numbers appear to the left of the RTB.

        // For the left edge to remain fixed,
        // this.Location.X  must remain constant.
        // Move the left border of the RTB and resize it,
        // as necessary.

        var newParentLoc = zParent.Location;
        newParentLoc.X = zNewLocation.X + zNewSize.Width + 1;
        zParent.Location = newParentLoc;
    }
    else if (zDockSide == LineNumberDockSide.Right)
    {
        // The line numbers appear to the right of the RTB.

        // For the right edge to remain fixed,
        // this.Location.X + this.Width must remain constant
        // Move the right border of the RTB as necessary (hence,
        // resize it).
        zNewLocation.X = this.Location.X - delta;
    }
    zParent.Size = newParentSize;
    this.Location = zNewLocation;
    this.Size = zNewSize;
}

AnswerRe: line numbers disappear when the # of lines is large?memberDamian J. Suess10 Apr '10 - 7:05 
Thank you for the update! Testing it out now. I'm still unhappy with the overall update mechanism in general. Don't get me wrong, your contribution was awesome! Smile | :)
 
Going to look into different routes of updating the line count with as little over-head as possible. As we all noticed, it begins to choke a little after ~15000 lines.
-code monkey-

GeneralRe: line numbers disappear when the # of lines is large?memberCheeso20 Apr '10 - 4:14 
Damian, after looking at this further, I thought to try a different tack.
Rather than defining a companion control, as you did here, I extended RichTextBox. This RichTextBoxEx displays line numbers itself, within its bounds, in response to the Paint event. Some pictures.
 
http://i39.tinypic.com/13zcoz6.jpg[^]
 
http://i43.tinypic.com/wml2z9.jpg[^]
 
http://i39.tinypic.com/25i4x3o.jpg[^]
 
It scrolls cleanly, it's fast.
 
You can get the code to see what I did, here:
http://xpathvisualizer.codeplex.com/SourceControl/changeset/view/42057#823009[^]
 
Also this one is under source control, so if anyone wants to submit requests or bugs, it's available to you.
BugRe: line numbers disappear when the # of lines is large?memberHirnhamster16 Jan '12 - 2:10 
First of all, great work Smile | :) Really helped me a lot Wink | ;)
 
But there are two minor bugs in your code:
1. If the first character is a New-Line, the first line number is "2" instead of "1". I fixed it by changing
 
private int FirstVisibleTextLine
 {
     get
     {
         int c = GetCharIndexFromPos(1,1);
         for (int i=0; i < CharIndexForTextLine.Length; i++)
         {
             if (c < CharIndexForTextLine[i]) return i;
         }
         return CharIndexForTextLine.Length;
     }
 }
 
to
 
private int FirstVisibleTextLine
 {
     get
     {
         int c = GetCharIndexFromPos(1,1);
         for (int i=0; i < CharIndexForTextLine.Length; i++)
         {
             if (c <= CharIndexForTextLine[i]) return i;
         }
         return CharIndexForTextLine.Length;
     }
 }
 
(replacing c < by c <=) - I have not tested this exhaustively, but I didn't face any problems with this solution so far.
 
2. If the line-numbers increase the number of digits (e.g. from 9 to 10), the size of the line-number-space is not calculated correctly. If you add another line (e.g. from 10 to 11), it works as expected.
 
As a solution, I changed
 
private int LineNumberWidth
{
    get
    {
        if (_lnw > 0) return _lnw;
        if (NumberLineCounting == LineCounting.CRLF)
        {
            _ndigits = (CharIndexForTextLine.Length == 0)
                ? 1
                : (int)(1 + Math.Log((double)CharIndexForTextLine.Length, 10));
        }
//...
}
 
to
 
private int LineNumberWidth
{
    get
    {
        if (_lnw &gt; 0) return _lnw;
        if (NumberLineCounting == LineCounting.CRLF)
        {
            _ndigits = (CharIndexForTextLine.Length == 0)
                ? 1
                : (int)(1 + Math.Log((double)CharIndexForTextLine.Length+1, 10));
        }
//...
}
 
(adding a "+1" before calculating the log10, because _n-New Line's correspond to _n+1 displayed lines)
 
Hope that helps Smile | :)
 
Cheers
Pascal

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130516.1 | Last Updated 11 Aug 2009
Article Copyright 2009 by Damian J. Suess
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid