How do I automatically scroll to the bottom of a multiline text box?
Solution 1
At regular intervals, I am adding new lines of text to it. I would like the textbox to automatically scroll to the bottom-most entry (the newest one) whenever a new line is added.
If you use TextBox.AppendText(string text)
, it will automatically scroll to the end of the newly appended text. It avoids the flickering scrollbar if you're calling it in a loop.
It also happens to be an order of magnitude faster than concatenating onto the .Text
property. Though that might depend on how often you're calling it; I was testing with a tight loop.
This will not scroll if it is called before the textbox is shown, or if the textbox is otherwise not visible (e.g. in a different tab of a TabPanel). See TextBox.AppendText() not autoscrolling. This may or may not be important, depending on if you require autoscroll when the user can't see the textbox.
It seems that the alternative method from the other answers also don't work in this case. One way around it is to perform additional scrolling on the VisibleChanged
event:
textBox.VisibleChanged += (sender, e) =>
{
if (textBox.Visible)
{
textBox.SelectionStart = textBox.TextLength;
textBox.ScrollToCaret();
}
};
Internally, AppendText
does something like this:
textBox.Select(textBox.TextLength + 1, 0);
textBox.SelectedText = textToAppend;
But there should be no reason to do it manually.
(If you decompile it yourself, you'll see that it uses some possibly more efficient internal methods, and has what seems to be a minor special case.)
Solution 2
You can use the following code snippet:
myTextBox.SelectionStart = myTextBox.Text.Length;
myTextBox.ScrollToCaret();
which will automatically scroll to the end.
Solution 3
It seems the interface has changed in .NET 4.0. There is the following method that achieves all of the above. As Tommy Engebretsen suggested, putting it in a TextChanged event handler makes it automatic.
textBox1.ScrollToEnd();
Solution 4
textBox1.Focus()
textBox1.SelectionStart = textBox1.Text.Length;
textBox1.ScrollToCaret();
didn't work for me (Windows 8.1, whatever the reason).
And since I'm still on .NET 2.0, I can't use ScrollToEnd.
But this works:
public class Utils
{
[System.Runtime.InteropServices.DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
private static extern int SendMessage(System.IntPtr hWnd, int wMsg, System.IntPtr wParam, System.IntPtr lParam);
private const int WM_VSCROLL = 0x115;
private const int SB_BOTTOM = 7;
/// <summary>
/// Scrolls the vertical scroll bar of a multi-line text box to the bottom.
/// </summary>
/// <param name="tb">The text box to scroll</param>
public static void ScrollToBottom(System.Windows.Forms.TextBox tb)
{
if(System.Environment.OSVersion.Platform != System.PlatformID.Unix)
SendMessage(tb.Handle, WM_VSCROLL, new System.IntPtr(SB_BOTTOM), System.IntPtr.Zero);
}
}
VB.NET:
Public Class Utils
<System.Runtime.InteropServices.DllImport("user32.dll", CharSet := System.Runtime.InteropServices.CharSet.Auto)> _
Private Shared Function SendMessage(hWnd As System.IntPtr, wMsg As Integer, wParam As System.IntPtr, lParam As System.IntPtr) As Integer
End Function
Private Const WM_VSCROLL As Integer = &H115
Private Const SB_BOTTOM As Integer = 7
''' <summary>
''' Scrolls the vertical scroll bar of a multi-line text box to the bottom.
''' </summary>
''' <param name="tb">The text box to scroll</param>
Public Shared Sub ScrollToBottom(tb As System.Windows.Forms.TextBox)
If System.Environment.OSVersion.Platform <> System.PlatformID.Unix Then
SendMessage(tb.Handle, WM_VSCROLL, New System.IntPtr(SB_BOTTOM), System.IntPtr.Zero)
End If
End Sub
End Class
Solution 5
I needed to add a refresh:
textBox1.SelectionStart = textBox1.Text.Length;
textBox1.ScrollToCaret();
textBox1.Refresh();
GWLlosa
Widely experienced .NET/Data developer moving to Denver for a fresh start.
Updated on July 08, 2022Comments
-
GWLlosa almost 2 years
I have a textbox with the .Multiline property set to true. At regular intervals, I am adding new lines of text to it. I would like the textbox to automatically scroll to the bottom-most entry (the newest one) whenever a new line is added. How do I accomplish this?
-
GWLlosa almost 15 yearsLooked here for the answer, couldn't find it, so when I figured it out, I figured I'd put it up here for future users, or if maybe someone else had a better approach.
-
Bob about 11 yearsNote that that method is in the
TextBoxBase
class in theSystem.Windows.Controls.Primitives
namespace (PresentationFramework
assembly, WPF). This method does not exist and will not work in WinForms, whoseTextBox
class inherits fromTextBoxBase
in theSystem.Windows.Forms
namespace (System.Windows.Forms
assembly, WinForms). -
tomsv almost 11 yearsThis may have been the best answer at the time, but now I think Bob's answer is a better solution to the OP's problem.
-
EMBEDONIX over 10 yearsWas eating myself trying to make it with
tb.Text += ....
and WndProc and marshals Now I feel stupid :D -
hello_earth about 10 yearsstill, for me (.NET 3.5) things only worked when I added the suggested code with SelectionStart & ScrollToCaret to TextChanged event handler (see below), because otherwise at some point (not always), the scroll would be reset to the beginning (probably the best solution would be to override that default code..)
-
Bob about 10 years@hello_earth I have updated with a workaround for the case where the textbox is not scrolling while invisible. You can try and see if that works for you.
-
Qwerty01 about 10 yearsThe textarea also needs to be focused, the first time I did this it did not scroll because it did not have the focus.
-
Shawn Kovac over 9 yearsi was setting the text in the Form's Load event. i was unable to get my
TextBox
to scroll to the bottom when i puttxtInfo.SelectionStart = txtInfo.Text.Length; txtInfo.ScrollToCaret(); txtInfo.Refresh();
in the Load event. i tried to put this code in theTextBox
's VisibleChanged event too, to no avail. what i did that worked was putting this code (txtInfo.SelectionStart = txtInfo.Text.Length; txtInfo.ScrollToCaret();
) in a timer tick event & then start that timer at the end of the Load event. it worked even with 1 ms delay. not sure why it just didn't work for me in the Load event. -
TooGeeky over 9 yearsI know, it is similar to Bob's answer, but explains a specific case. AND I can't comment on Bob's answer... Stuck with stackoverflow rules :(
-
Elshan almost 9 years
textBox.VisibleChanged
not work.But I change that into txtResponse.TextChanged and it's work. -
John over 8 years@Bob thanks for the tip. Works great! I would add that you might want to add Environment.Newline to each string added.
-
Hannes over 8 yearsHad the same issue with Windows 10, your workaround works fine here too.
-
Hugo Yates over 8 yearsI had the issue where it would refuse to scroll to the end. I was loading in a log file at the start of my application. The solution was to put the code from above answer in the 'Shown' event (ie
MyForm_Shown(object sender, EventArgs e)
). -
Brandon Barkley over 6 yearsAppendText did not automatically scroll my ReadOnly TextBox, but adding TextBox.ScrollToEnd(); after the AppendText call did the trick.
-
ergohack over 6 yearsNote that
ScrollToEnd()
can be extremely poor performing. In my app it accounted for over 50% of the profiling time. -
Leonardo Hernández over 2 yearsYou probably prefer to override the OnShown method: "protected override void OnShown (EventArgs e)" instead of putting an event handler for Activate.
-
Xavi over 2 yearsWorks for me (Windows 10) Thx
-
TByte about 2 yearsOther answers didn't work, this one did. Windows 10, 4.7.2.