Is there a simple way to limit the number of lines in a multi-line textbox that wraps I want to be able to look for soft returns as well as hard returns.
Yes, EM_GETLINECOUNT message is the one you are looking for. It returns total number of text lines in multilined TextBox/RichTextBox. For example: if you have single line of text wrapped into three lines, the message will return 3. Note that the message never returns value less than 1, it will return 1 in case of empty TextBox.
You know what I really miss I could swear that somewhere along the way before .NET shipped, the Control class had a SendMessage method. Man, that was nice. EM_GETLINECOUNT is definitely the most direct solution, but I do hate the P/Invoke stuff...
Good solution, given that they don't provide this information otherwise!
Thanks, Erymuzuan. Turning WordWrap off isn't an option. I've already implemented a MaxLength property which works reasonably well considering I'm not using a fixed-length font. The problem there is that users can still press Enter any number of times up to the MaxLength.
I found something about the SendMessage API function with the EM_GETLINECOUNT message but I haven't been able to get it to work yet. Before I delve any deeper, can anyone confirm that it does what I need it to do
Well, I think that TextBox.Lines property is all you need - read it carefully in the .NET Framework SDK. So, you may get the TextBox.Lines.Length and if it is higher than desired one - don't process enter key.
For what it's worth, here is how you could use the EM_GETLINECOUNT message:
Private Const EM_GETLINECOUNT As Integer = &HBA Private Declare Function SendMessageINT Lib "user32" Alias "SendMessageA" (ByVal hWnd as IntPtr, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
Unfortunately, EM_GETLINECOUNT must be sent using SendMessage, else you could use WndProc and Message.Create.
This could easily be integrated into your own textbox (with one caveat):
Public Class LimitLineTextBox Inherits TextBox
Private m_MaxLines As Integer = 1
Public Sub New() MyBase.New() Me.MultiLine = True End Sub
<DefaultValue(1), Category("Behavior")> _ Public Property MaxLines() As Integer Get Return m_MaxLines End Get Set(ByVal Value As Integer) If Value <= 0 Then Throw New Exception("The Value of the Max Lines Property must be greater than 0") Else m_MaxLines = Value End If End Set End Property
Protected Overrides Sub OnKeyPress(ByVal e As System.Windows.Forms.KeyPressEventArgs) Dim numLines As Integer = GetLineCount() If numLines > MaxLines Then e.Handled = True Else MyBase.OnKeyPress(e) End If End Sub
Private Declare Function SendMessageINT Lib "user32" Alias "SendMessageA" (ByVal hWnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
Private Function GetLineCount() As Integer Const EM_GETLINECOUNT As Integer = &HBA Return SendMessageINT(Me.Handle, EM_GETLINECOUNT, 0, 0) End Function End Class
The caveat is in the override of OnKeyPress. You'll notice that I check the line count to determine if it's greater than the max allowable lines. But, I do nothing to accomodate for the case when the line count equals the MaxLines. This might be a big hurdle. Also note that certain user actions such as resizing a form with this control anchored on it can result in the number of soft lines changing. Another potential hurdle...
Unfortunately, TextBox.Lines returns a collection of lines delimited with CR/LF--that is, it doesn't help if you need to determine how many WRAPPED lines there are. A new line starts when a user presses Enter. What's requested here (and what I've needed in the past) is a collection of the lines as they appear wrapped on screen. It always surprised me that there's no way to determine natively how many lines of text appear on the screen, without resorting to the Win32API.
i'm curious if there's a way to do it using GDI+'s MeasureString method...maybe pass it the region of the textbox and the font and divide by height of font bah...i dunno :~
i can't find a way to limit the number of line natively. but there are work around . if your textbox WordWrap is false then you could hook the Text_Change/Key_Press and count the newline. but in your case the best i could recommend is to limit the MaxLength property and estimate the number of characters there would be for a desired number of line
Limit number of lines in a TextBox
Rushi Amin
IBRAHIM ERSOY
It returns total number of text lines in multilined TextBox/RichTextBox. For example: if you have single line of text wrapped into three lines, the message will return 3.
Note that the message never returns value less than 1, it will return 1 in case of empty TextBox.
Thomas Schimming
Good solution, given that they don't provide this information otherwise!
virenkar
I found something about the SendMessage API function with the EM_GETLINECOUNT message but I haven't been able to get it to work yet. Before I delve any deeper, can anyone confirm that it does what I need it to do
Reeves
Well, I think that TextBox.Lines property is all you need - read it carefully in the .NET Framework SDK. So, you may get the TextBox.Lines.Length and if it is higher than desired one - don't process enter key.
Cheers,
Gogou
mnrsmith
Private Const EM_GETLINECOUNT As Integer = &HBA
Private Declare Function SendMessageINT Lib "user32" Alias "SendMessageA" (ByVal hWnd as IntPtr, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
Then to use it:
NumOfLines = SendMessageINT(TBox.Handle, EM_GETLINECOUNT, 0,0)
Unfortunately, EM_GETLINECOUNT must be sent using SendMessage, else you could use WndProc and Message.Create.
This could easily be integrated into your own textbox (with one caveat):
Public Class LimitLineTextBox
Inherits TextBox
Private m_MaxLines As Integer = 1
Public Sub New()
MyBase.New()
Me.MultiLine = True
End Sub
<DefaultValue(1), Category("Behavior")> _
Public Property MaxLines() As Integer
Get
Return m_MaxLines
End Get
Set(ByVal Value As Integer)
If Value <= 0 Then
Throw New Exception("The Value of the Max Lines Property must be greater than 0")
Else
m_MaxLines = Value
End If
End Set
End Property
Protected Overrides Sub OnKeyPress(ByVal e As System.Windows.Forms.KeyPressEventArgs)
Dim numLines As Integer = GetLineCount()
If numLines > MaxLines Then
e.Handled = True
Else
MyBase.OnKeyPress(e)
End If
End Sub
Private Declare Function SendMessageINT Lib "user32" Alias "SendMessageA" (ByVal hWnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
Private Function GetLineCount() As Integer
Const EM_GETLINECOUNT As Integer = &HBA
Return SendMessageINT(Me.Handle, EM_GETLINECOUNT, 0, 0)
End Function
End Class
The caveat is in the override of OnKeyPress. You'll notice that I check the line count to determine if it's greater than the max allowable lines. But, I do nothing to accomodate for the case when the line count equals the MaxLines. This might be a big hurdle. Also note that certain user actions such as resizing a form with this control anchored on it can result in the number of soft lines changing. Another potential hurdle...
Hope this is helpful.
Loren Jensen
Galex Yen - MSFT
Sync_Austin