WinForm RichTextbox 仅当滚动条插入符位于底部时自动滚动

问题描述 投票:0回答:1

我正在 Winforms 中使用 RichTextBox 来显示实时文本流。当新数据进来时,RichTextBox 向下滚动以显示最新添加的文本。

如果用户想要通过向上移动滚动条插入符来查看以前的数据,RichTextBox 将立即向上滚动,但进入的新文本会将其向下滚动。

我期望的行为与终端中使用的行为类似:

  • 如果滚动条插入符位于底部:在底部显示最新文本。
  • 如果滚动条插入符号不在底部:显示的文本被冻结,允许用户阅读该文本。如果他将滚动条插入符号移至底部,它将继续显示最新文本。

我在代码中使用

AppendText()
ScrollToCaret()

我尝试了类似问题的几种答案,但没有成功。

c# winforms scrollbar richtextbox caret
1个回答
0
投票

在我的一个项目中,我需要一个类似的解决方案,其中我使用

RichTextBox
来显示日志。如果我们稍微更新一下需求,问题就更容易解决了:

  • 如果滚动条光标插入符号位于底部:在底部显示最新文本。
  • 如果滚动条光标插入符号不在底部:显示的文本被冻结,允许用户阅读该文本。如果他将滚动条插入符号移至底部,它将继续显示最新文本。

这意味着您必须单击或导航到要修复的位置,而不仅仅是依赖滚动条位置。如果您导航回到底部(通过单击或按 Ctrl+End),那么您可以再次看到更新。

如果您可以接受这些要求,那么这里是一个可能的解决方案:

private void AppendText(string text, Color color)
{
    int len = _richTextBox.TextLength;

    // empty text box: trivial case
    if (len == 0)
    {
        _richTextBox.ForeColor = color;
        _richTextBox.Text = message;
        _richTextBox.SelectionStart = message.Length;
        return;
    }

    // Saving the original position of the cursor.
    // If it's not at the very end, then it must be reset after appending the text.
    var selStart = _richTextBox.SelectionStart;
    var selLength = _richTextBox.SelectionLength;
    var resetSelection = selStart != len;

    // Appending the text with the specified color at the bottom
    _richTextBox.SelectionStart = len;
    _richTextBox.SelectionColor = color;
    _richTextBox.AppendText(message);

    // Optional extra: removing lines from the top to prevent growing indefinitely
    // (RichTextBox can be really slow with more then 10K lines)
    int lines = _richTextBox.GetLineFromCharIndex(len = _richTextBox.TextLength);
    if (lines > MaxLines)
    {
        int removeLen = _richTextBox.GetFirstCharIndexFromLine(lines - MaxLines);
        _richTextBox.Select(0, removeLen);
        selStart -= removeLen;
        len -= removeLen;
        _richTextBox.ReadOnly = false;
        _richTextBox.SelectedText = String.Empty;
        _richTextBox.ReadOnly = true;
        if (selStart < 0)
            resetSelection = false;
    }

    // The key part: resetting the original position
    if (resetSelection)
    {
        _richTextBox.SelectionStart = selStart;
        _richTextBox.SelectionLength = selLength;
    }
    else
        _richTextBox.SelectionStart = len;
}
© www.soinside.com 2019 - 2024. All rights reserved.