qt8gt0bxhw|20009F4EEE83|RyanMain|subtext_Content|Text|0xfbffbc0000000000a800000001000400
A while back I helped a friend with determining how to count the number of lines contained in the TextBox. He needed to count each line - whether it was a line wrapped from the line above it, or from a carriage return to start a new line. The problem is that most ways to count lines in a TextBox will only count actual new lines, or lines that are a result of a carriage return. Not the lines as the result from a line wrap as these are not typically seen as their own lines. Also, if the TextBox is resized, then the line count needs to refect the number of lines at that moment.
Not a difficult task, however, it does require a bit of magic ala Windows messages. To make this as clean as possible, let's just inherit from TextBox to give it a new property to get the number of lines displayed in the TextBox. While we are at it, let's add properties for LineIndex and LineLength so we can determine the lenth of a given line. Exposing the LineIndex will allow us to loop through the lines in the TextBox. We'll use the EM_GETLINECOUNT message to retrieve the number of lines in the TextBox, the EM_LINEINDEX message to get the index of a line and EM_LINELENGTH to get the length of a given line. Then all we'll need to do is wrap these up in a messages and pump them off to Windows via the base TextBox's DefWndProc method. Take a look at the complete & new TextBox control:
using System;
using System.Windows.Forms;
namespace TextBoxLines
{
public class TextBoxEx : TextBox
{
private const int EM_GETLINECOUNT = 0xBA;
private const int EM_LINEINDEX = 0xBB;
private const int EM_LINELENGTH = 0xC1;
public TextBoxEx() :base()
{
//Since we'll want multiple lines allowed we'll add that to the constructor
this.Multiline = true;
this.ScrollBars = ScrollBars.Vertical;
}
public int LineCount
{
get
{
Message msg = Message.Create(this.Handle, EM_GETLINECOUNT, IntPtr.Zero, IntPtr.Zero);
base.DefWndProc(ref msg);
return msg.Result.ToInt32();
}
}
public int LineIndex(int Index)
{
Message msg = Message.Create(this.Handle, EM_LINEINDEX, (IntPtr)Index, IntPtr.Zero);
base.DefWndProc(ref msg);
return msg.Result.ToInt32();
}
public int LineLength(int Index)
{
Message msg = Message.Create(this.Handle, EM_LINELENGTH, (IntPtr)Index, IntPtr.Zero);
base.DefWndProc(ref msg);
return msg.Result.ToInt32();
}
}
}
Just beautiful. Now you have them built into the TextBox. Use them just as you would use any property for the TextBox and get the number of lines displayed in the TextBox - doesn't matter if they are wrapped lines or actual lines. You can download this code in a sample project below.
TextBoxLines sample project