On a TextBox I can calculate the number on lines with the following code:
Private Sub TextBox1_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox1.TextChanged linecount = SendMessage(TextBox1.Handle.ToInt32, EM_GETLINECOUNT, -1, 0) lblLine1.Text = "Line Count: " & (linecount).ToString lblLine2.Text = "Char Count: " & TextBox1.Text.Length If linecount > 6 Then TextBox1.Focus() SendKeys.Send("{BKSP}") End If End Sub
When I use an UltraTextEditor control the code does not work.
I need to restrict the number the lines. Is there a way to do this?
John
Not to take away from the valuable information already shared, but isn't using the Win32 API for something as trivial as a line count a little over the top?
Another way to impose a line limit is to use the KeyDown event on the UltraTextEditor. Using this event we can call a method to get the line count, and then allow the key press or suppress it.
C#
private int CountLinesInString(string s) { int count = 1, start = 0; while ((start = s.IndexOf('\n', start)) != -1) { count++; start++; } return count; } private const int MAXLINES = 6; private void txtEditor_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Back) return; String PendingValue = txtEditor.Text + (char)e.KeyValue; if (CountLinesInString(PendingValue) > MAXLINES) e.SuppressKeyPress = true; }
VB
Private Function CountLinesInString(s As String) As Integer Dim count As Integer = 1, start As Integer = 0 While (InlineAssignHelper(start, s.IndexOf(ControlChars.Lf, start))) <> -1 count += 1 start += 1 End While Return count End Function Private Const MAXLINES As Integer = 6 Private Sub txtEditor_KeyDown(sender As Object, e As KeyEventArgs) If e.KeyCode = Keys.Back Then Return End If Dim PendingValue As [String] = txtEditor.Text + CChar(e.KeyValue) If CountLinesInString(PendingValue) > MAXLINES Then e.SuppressKeyPress = True End If End Sub
Hi,
Okay, I am able to see the problem using the code you posted here. As I suspected, this is a timing issue. When the control is not in edit mode and therefore there is no inbox TextBox control, UltraTextEditor uses it's UIElements to determine the line count.
The problem here is that when you change the text and the TextChanged event fire, the display has not yet been updated. The control hasn't painted, yet, with the new text. So it's still using the old text and the old UIElements to measure.
You can get around this very easily by simply calling the Update method to force the control to redraw if needed right before you call SendMessage.
public static void AdaptHeight(Control ut) { ut.Update(); var rows = (int)SendMessage(ut.Handle, EM_GETLINECOUNT, IntPtr.Zero, IntPtr.Zero); ut.Height = rows * ut.Font.Height + 1 + ut.Margin.Vertical; }
Hello Mike, here is what I managed to reproduce so far. Just copy paste below in an empty class file.
Its a form with two buttons and a UltraTextBox.
When you type in the UltraTextBox using a couple of carriage returns, notice its height will adjust itself :
=> this works fine
Unfortunately, when you use the "Add Lines" button to add some lines, you will see that it is no longer the case.
=> here is the bug
When swiching the focus through all the control, I notice that the text in the UltraTextBox changes : all the RC disappears.
It sounds like the embedded TextBox is no longer in sync with the other one.
using System; using System.Runtime.InteropServices; using System.Windows.Forms; namespace WindowsFormsApplication4 { public class Form1 : Form { private Infragistics.Win.UltraWinEditors.UltraTextEditor ultraTextEditor1 = new Infragistics.Win.UltraWinEditors.UltraTextEditor(); private Infragistics.Win.Misc.UltraButton Clear = new Infragistics.Win.Misc.UltraButton(); private Infragistics.Win.Misc.UltraButton AddLine = new Infragistics.Win.Misc.UltraButton(); public Form1() { this.ultraTextEditor1.Location = new System.Drawing.Point(12, 13); this.ultraTextEditor1.Multiline = true; this.ultraTextEditor1.Name = "ultraTextEditor1"; this.ultraTextEditor1.Size = new System.Drawing.Size(277, 78); this.ultraTextEditor1.TextChanged += new System.EventHandler(this.ultraTextEditor1_TextChanged); this.Clear.Location = new System.Drawing.Point(295, 41); this.Clear.Name = "Clear"; this.Clear.Size = new System.Drawing.Size(134, 22); this.Clear.Text = "clear text"; this.Clear.Click += new System.EventHandler(this.Clear_Click); this.AddLine.Location = new System.Drawing.Point(295, 13); this.AddLine.Name = "Add Lines"; this.AddLine.Size = new System.Drawing.Size(134, 22); this.AddLine.Text = "Add lines"; this.AddLine.Click += new System.EventHandler(this.ultraButton1_Click); this.ClientSize = new System.Drawing.Size(438, 232); this.Controls.Add(this.Clear); this.Controls.Add(this.AddLine); this.Controls.Add(this.ultraTextEditor1); this.Name = "Form1"; this.Text = "Test form"; } private void Clear_Click(object sender, EventArgs e) { ultraTextEditor1.Clear(); } const int EM_GETLINECOUNT = 0xBA; public static void AdaptHeight(Control ut) { var rows = (int)SendMessage(ut.Handle, EM_GETLINECOUNT, IntPtr.Zero, IntPtr.Zero); ut.Height = rows * ut.Font.Height + 1 + ut.Margin.Vertical; } [DllImport("user32.dll", CharSet = CharSet.Auto)] static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam); private void ultraTextEditor1_TextChanged(object sender, EventArgs e) { AdaptHeight(ultraTextEditor1); } private void ultraButton1_Click(object sender, EventArgs e) { var txt = ultraTextEditor1.Text; ultraTextEditor1.Text = txt += "bla\nblabla\nblablabla"; // AdaptHeight(ultraTextEditor1); } } }
That's possible, but without being able to see this bug actually occurring, I'm not sure how that could be the case.
When the UltraTextEditor is in edit mode, getting the line count is actually just a simple matter of passing off the Windows API message to the embedded TextBox control within the UltraTextEditor. So if this is failing, it's the inbox TextBox control that is failing. If that's the case, then my best guess is that there is some sort of timing issue regarding when you are calling the method.
If you can post a sample demonstrating this not working, I would be happy to take a look at it.
I tried to put the AutoSize function everywhere I could, inside, outside the text_changed event, and I cannot make it work except when typing inside.
I replaced the ultratexteditor by a standard winform RichTextBox and it works fine... I am using a scenario where controls are created a dynamic way. Perhaps some tricky situations are not well handled yet by the ultratexteditor ?