不一致的结果与RichTextBox ScrollToCaret

本文关键字:RichTextBox ScrollToCaret 结果 不一致 | 更新日期: 2023-09-27 18:18:16

我正在使用c#中的RichTextBox。它存在于TabPage中。当TabPage被选中时,我的目标是填充RichTextBox,并滚动到最后。对于这个常见的问题,我尝试了一些稍微不同的解决方案,主要的是:

MyRichTextBox.Select(MyRichTextBox.Text.Length, 0);  
MyRichTextBox.ScrollToCaret();  

或:

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

这会产生不一致的结果,尽管是以可预测的方式。它将在滚动到底部和滚动到底部一行之间交替。分别说明(抱歉链接,新用户,所以我不能发布图像):
成功滚动到底部
滚动到距底部短一行
我很惊讶地发现,通过我的搜索没有提到这种行为,并决定问是否有人在这里遇到过这种情况,和/或有一个解决方案。如果归结到这一点,我想我可以用一些类似于它的答案。

不一致的结果与RichTextBox ScrollToCaret

我对ScrollToCaret做了一些进一步的实验,它并不是每次都在相同的位置结束。因为我的目标是只滚动到底部,它是一个很好的候选人发送WM_VSCROLL消息(277,或0x115)到控件,与wParam的SB_PAGEBOTTOM(7)。这始终如一地滚动到最底部,就像我需要的那样:

[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam);
private const int WM_VSCROLL = 277;
private const int SB_PAGEBOTTOM = 7;
public static void ScrollToBottom(RichTextBox MyRichTextBox)
{
    SendMessage(MyRichTextBox.Handle, WM_VSCROLL, (IntPtr)SB_PAGEBOTTOM, IntPtr.Zero);
}

将其更改为适合您的工作代码…

String gotoCaret = "Something on this line.";
int position = textBox.Text.IndexOf(gotoCaret);
MyRichTextBox.SelectionStart = position;
MyRichTextBox.ScrollToCaret();

我也有同样的问题,我猜RTB几乎是由Windows Messages管理的,所以它听起来有点像兔子沃伦。因此,我不知道交替输出的原因(但它有点bug的味道)。我很关心这个RTB。但在一个VB程序的滚动插入闪烁输出。赞美你的极端解决方案:效果很好。

如果有人在编程环境中遇到这种异常,这里是VB代码

Imports System.Runtime.InteropServices
Public Class Form
<DllImport("user32.dll",CharSet:=CharSet.Auto)> _
Public Shared Function SendMessage( _
ByVal hWnd As IntPtr, _
ByVal wMsg As Integer, _
ByVal wParam As IntPtr, _
ByVal lParam As IntPtr) As Integer
End Function
Const WM_SCROLL = 277
Const SB_PAGEBOTTOM = 7
Sub ScrollToBottom(ByVal RTBName As RichTextBox)
   SendMessage(RTBName.Handle, _
               WM_SCROLL, _
               SB_PAGEBOTTOM, _
               IntPtr.Zero)
End Sub 'then call ScrollToBottom instead of ScrollToCaret

我遇到了同样的错误(现在已经有7年多了),ScrollToCaret()在最后一行和几乎最后一行之间交替跳转。另一个避免使用非托管代码的解决方案是调用ScrollToCaret()两次。

RichBox.Select(TheLocationYouWantToScrollTo, 0);
RichBox.ScrollToCaret();
RichBox.ScrollToCaret();

这种方法有时会产生一点屏幕闪烁(不错,但不是超级平滑),因为它滚动到一行,然后另一行。您可以尝试用这种方法解决轻微的闪烁,但它不起作用:

RichBox.SuspendLayout(); // I won't actually suspend this layout
RichBox.Select(TheLocationYouWantToScrollTo, 0);
RichBox.ScrollToCaret();
RichBox.ScrollToCaret();
RichBox.ResumeLayout();

你也可以通过确保新的位置在新的一行来减少闪烁:

RichBox.Select(TheLocationYouWantToScrollTo, 0)
if (RichBox.Transcription.GetFirstCharIndexOfCurrentLine() != ThePriorCharIndexOfCurrentLine)
{
   RichBox.ScrollToCaret();
   RichBox.ScrollToCaret(); 
}

这减少闪烁,只有当我们在一个新的行滚动。