[c#] How do I automatically scroll to the bottom of a multiline text box?

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?

This question is related to c# winforms textbox scroll

The answer is


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

You can use the following code snippet:

myTextBox.SelectionStart = myTextBox.Text.Length;
myTextBox.ScrollToCaret();

which will automatically scroll to the end.


For anyone else landing here expecting to see a webforms implementation, you want to use the Page Request Manager's endRequest event handler (https://stackoverflow.com/a/1388170/1830512). Here's what I did for my TextBox in a Content Page from a Master Page, please ignore the fact that I didn't use a variable for the control:

var prm = Sys.WebForms.PageRequestManager.getInstance();

function EndRequestHandler() {
    if ($get('<%= ((TextBox)StatusWindow.FindControl("StatusTxtBox")).ClientID %>') != null) {
        $get('<%= ((TextBox)StatusWindow.FindControl("StatusTxtBox")).ClientID %>').scrollTop = 
        $get('<%= ((TextBox)StatusWindow.FindControl("StatusTxtBox")).ClientID %>').scrollHeight;
    }
}

prm.add_endRequest(EndRequestHandler);

With regards to the comment by Pete about a TextBox on a tab, the way I got that to work was adding

textBox1.SelectionStart = textBox1.Text.Length;
textBox1.ScrollToCaret();

to the tab's Layout event.


I needed to add a refresh:

textBox1.SelectionStart = textBox1.Text.Length;
textBox1.ScrollToCaret();
textBox1.Refresh();

I found a simple difference that hasn't been addressed in this thread.

If you're doing all the ScrollToCarat() calls as part of your form's Load() event, it doesn't work. I just added my ScrollToCarat() call to my form's Activated() event, and it works fine.

Edit

It's important to only do this scrolling the first time form's Activated event is fired (not on subsequent activations), or it will scroll every time your form is activated, which is something you probably don't want.

So if you're only trapping the Activated() event to scroll your text when your program loads, then you can just unsubscribe to the event inside the event handler itself, thusly:

Activated -= new System.EventHandler(this.Form1_Activated);

If you have other things you need to do each time your form is activated, you can set a bool to true the first time your Activated() event is fired, so you don't scroll on subsequent activations, but can still do the other things you need to do.

Also, if your TextBox is on a tab that isn't the SelectedTab, ScrollToCarat() will have no effect. So you need at least make it the selected tab while you're scrolling. You can wrap the code in a YourTab.SuspendLayout(); and YourTab.ResumeLayout(false); pair if your form flickers when you do this.

End of edit

Hope this helps!


This will scroll to the end of the textbox when the text is changed, but still allows the user to scroll up

outbox.SelectionStart = outbox.Text.Length;
outbox.ScrollToEnd();

tested on Visual Studio Enterprise 2017


Try to add the suggested code to the TextChanged event:

private void textBox1_TextChanged(object sender, EventArgs e)
{
  textBox1.SelectionStart = textBox1.Text.Length;
  textBox1.ScrollToCaret();
}

This only worked for me...

txtSerialLogging->Text = "";

txtSerialLogging->AppendText(s);

I tried all the cases above, but the problem is in my case text s can decrease, increase and can also remain static for a long time. static means , static length(lines) but content is different.

So, I was facing one line jumping situation at the end when the length(lines) remains same for some times...


I use a function for this :

private void Log (string s) {
    TB1.AppendText(Environment.NewLine + s);
    TB1.ScrollToCaret();
}

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();

Examples related to c#

How can I convert this one line of ActionScript to C#? Microsoft Advertising SDK doesn't deliverer ads How to use a global array in C#? How to correctly write async method? C# - insert values from file into two arrays Uploading into folder in FTP? Are these methods thread safe? dotnet ef not found in .NET Core 3 HTTP Error 500.30 - ANCM In-Process Start Failure Best way to "push" into C# array

Examples related to winforms

How to set combobox default value? Get the cell value of a GridView row Getting the first and last day of a month, using a given DateTime object Check if a record exists in the database Delete a row in DataGridView Control in VB.NET How to make picturebox transparent? Set default format of datetimepicker as dd-MM-yyyy Changing datagridview cell color based on condition C# Inserting Data from a form into an access Database How to use ConfigurationManager

Examples related to textbox

Add two numbers and display result in textbox with Javascript How to check if a text field is empty or not in swift Setting cursor at the end of any text of a textbox Press enter in textbox to and execute button command javascript getting my textbox to display a variable How can I set focus on an element in an HTML form using JavaScript? jQuery textbox change event doesn't fire until textbox loses focus? PHP: get the value of TEXTBOX then pass it to a VARIABLE How to clear a textbox once a button is clicked in WPF? Get current cursor position in a textbox

Examples related to scroll

How to window.scrollTo() with a smooth effect Angular 2 Scroll to bottom (Chat style) Scroll to the top of the page after render in react.js Get div's offsetTop positions in React RecyclerView - How to smooth scroll to top of item on a certain position? Detecting scroll direction How to disable RecyclerView scrolling? How can I scroll a div to be visible in ReactJS? Make a nav bar stick Disable Scrolling on Body