Как автоматически перейти к нижней части многострочного текстового поля?

У меня есть текстовое поле с свойством .Multiline, равным true. Через определенные промежутки времени я добавляю к нему новые строки текста. Я хотел бы, чтобы текстовое поле автоматически прокручивалось до самой нижней записи (самой новой) всякий раз, когда добавляется новая строка. Как это сделать?

Ответ 1

Через регулярные промежутки времени я добавляю к нему новые строки текста. Я бы хотел, чтобы текстовое поле автоматически прокручивалось до самой нижней записи (самой новой) всякий раз, когда добавляется новая строка.

Если вы используете TextBox.AppendText(string text), он автоматически перейдет к концу вновь добавленного текста. Это позволяет избежать мерцающей полосы прокрутки, если вы вызываете ее в цикле.

Он также оказывается на порядок быстрее, чем конкатенация на свойство .Text. Хотя это может зависеть от того, как часто вы это называете; Я тестировал плотную петлю.


Это не будет прокручиваться, если оно вызывается до отображения текстового поля или если текстовое поле в противном случае не отображается (например, на другой вкладке TabPanel). См. TextBox.AppendText(), а не автопрокрутку. Это может быть или не быть важным, в зависимости от того, требуется ли вам автосканирование, когда пользователь не может видеть текстовое поле.

Кажется, что альтернативный метод из других ответов также не работает в этом случае. Один из способов - выполнить дополнительную прокрутку в событии VisibleChanged:

textBox.VisibleChanged += (sender, e) =>
{
    if (textBox.Visible)
    {
        textBox.SelectionStart = textBox.TextLength;
        textBox.ScrollToCaret();
    }
};

Внутри, AppendText делает что-то вроде этого:

textBox.Select(textBox.TextLength + 1, 0);
textBox.SelectedText = textToAppend;

Но не должно быть причин для этого вручную.

(Если вы декомпилируете его самостоятельно, вы увидите, что он использует некоторые, возможно, более эффективные внутренние методы и имеет то, что кажется небольшим частным случаем.)

Ответ 2

Вы можете использовать следующий фрагмент кода:

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

который будет автоматически прокручиваться до конца.

Ответ 3

Кажется, интерфейс изменился в .NET 4.0. Существует следующий

Ответ 4

Попробуйте добавить предлагаемый код к событию TextChanged:

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

Ответ 5

Мне нужно было добавить обновление:

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

Ответ 6

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

не работал у меня (Windows 8.1, независимо от причины).
И поскольку я все еще на .NET 2.0, я не могу использовать ScrollToEnd.

Но это работает:

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

Ответ 7

Я нашел простое отличие, которое не было рассмотрено в этом потоке.

Если вы выполняете все вызовы ScrollToCarat() как часть вашего события формы Load(), это не работает. Я просто добавил свой вызов ScrollToCarat() к моему событию формы Activated(), и он отлично работает.

Edit

Важно пропустить только прокрутку первой формы формы Activated (не при последующих активациях), или она будет прокручивать каждый, когда ваша форма активирована, что вы, вероятно, не хочу.

Итак, если вы только улавливаете событие Activated() для прокрутки текста при загрузке своей программы, вы можете просто отказаться от подписки на событие внутри самого обработчика событий, таким образом:

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

Если у вас есть другие вещи, которые вам нужно делать каждый раз, когда ваша форма активирована, вы можете установить значение bool в true при первом запуске вашего события Activated(), чтобы вы не прокручивали последующие активации, но все еще могут делать другие вещи, которые вам нужно сделать.

Кроме того, если ваш TextBox находится на вкладке, которая не является SelectedTab, ScrollToCarat() не будет иметь никакого эффекта. Поэтому вам нужно хотя бы сделать выбранную вкладку во время прокрутки. Вы можете обернуть код в пару YourTab.SuspendLayout(); и YourTab.ResumeLayout(false);, если ваша форма мерцает, когда вы это делаете.

Конец редактирования

Надеюсь, это поможет!

Ответ 8

Это приведет к прокрутке до конца текстового поля при изменении текста, но позволяет пользователю прокручивать вверх

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

протестирован на Visual Studio Enterprise 2017

Ответ 9

Для тех, кто приземляется здесь, ожидая увидеть реализацию webforms, вы хотите использовать обработчик события endRequest менеджера запросов (fooobar.com/questions/1277467/...). Вот что я сделал для своего TextBox на странице содержимого с главной страницы, пожалуйста, проигнорируйте тот факт, что я не использовал переменную для элемента управления:

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

Ответ 10

Это работало только для меня...

txtSerialLogging- > Text = "";

txtSerialLogging- > AppendText (с);

Я пробовал все вышеперечисленные случаи, но проблема в том, что текст s может уменьшаться, увеличиваться и также может оставаться статичным в течение длительного времени. статические значения, статическая длина (строки), но содержимое отличается.

Итак, я столкнулся с ситуацией с одной строкой в ​​конце, когда длина (линии) остается такой же в течение нескольких времен...

Ответ 11

Я использую для этого функцию:

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