it-swarm.com.ru

Как автоматически прокрутить до конца многострочного текстового поля?

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

261
GWLlosa

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

Если вы используете 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;

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

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

373
Bob

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

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

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

140
GWLlosa

Кажется, интерфейс изменился в .NET 4.0. Существует следующее метод , которое достигает всего вышеперечисленного. Как предложил Томми Энгебретсен, помещение его в обработчик событий TextChanged делает его автоматическим.

textBox1.ScrollToEnd();
39
JohnDRoach

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

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

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

textBox1.SelectionStart = textBox1.Text.Length;
textBox1.ScrollToCaret();
textBox1.Refresh();
8
h4nd
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
8
Stefan Steiger

Я нашел простую разницу, которая не была рассмотрена в этой теме.

Если вы делаете все вызовы 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);, если ваша форма мерцает при этом.

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

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

3
Pete

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

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

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

1
Eric Shreve

Для тех, кто находится здесь, ожидающих увидеть реализацию веб-форм, вы хотите использовать обработчик событий endRequest менеджера запросов страниц ( https://stackoverflow.com/a/1388170/1830512 ). Вот что я сделал для своего 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);
1
G.P. Greenleaf

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

txtSerialLogging-> Text = "";

txtSerialLogging-> AppendText (ы);

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

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

0
TooGeeky

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

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