我正在 Winforms 中使用 RichTextBox 来显示实时文本流。当新数据进来时,RichTextBox 向下滚动以显示最新添加的文本。
如果用户想要通过向上移动滚动条插入符来查看以前的数据,RichTextBox 将立即向上滚动,但进入的新文本会将其向下滚动。
我期望的行为与终端中使用的行为类似:
我在代码中使用
AppendText()
和 ScrollToCaret()
。
我尝试了类似问题的几种答案,但没有成功。
在我的一个项目中,我需要一个类似的解决方案,其中我使用
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;
}