我有一个文本框,其.Multiline属性设置为true。我会定期添加新的文本行。我希望每当添加新行时,文本框都会自动滚动到最底部的条目(最新的条目)。我该如何做到这一点?
我会定期添加新的文本行。我希望每当添加新行时,文本框都会自动滚动到最底部的条目(最新的条目)。
如果使用 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;
但是没有理由手动完成。
(如果你自己反编译,你会发现它使用了一些可能更有效的内部方法,并且具有似乎是一个小的特殊情况。)
您可以使用以下代码段:
myTextBox.SelectionStart = myTextBox.Text.Length;
myTextBox.ScrollToCaret();
它将自动滚动到结尾。
尝试将建议的代码添加到TextChanged事件:
private void textBox1_TextChanged(object sender, EventArgs e)
{
textBox1.SelectionStart = textBox1.Text.Length;
textBox1.ScrollToCaret();
}
我需要添加刷新:
textBox1.SelectionStart = textBox1.Text.Length;
textBox1.ScrollToCaret();
textBox1.Refresh();
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
我发现这个线程中没有解决的简单差异。
如果您在表单的ScrollToCarat()
事件中执行所有Load()
调用,则它不起作用。我刚刚将ScrollToCarat()
调用添加到我的表单的Activated()
事件中,它运行正常。
编辑
重要的是只在第一次触发表单的Activated
事件时进行滚动(而不是在后续激活中),或者它将滚动 每次 时间激活您的表单,这是您可能不想要的。
因此,如果您只是在程序加载时捕获Activated()
事件来滚动文本,那么您只需取消订阅事件处理程序本身内的事件即可:
Activated -= new System.EventHandler(this.Form1_Activated);
如果每次激活表单时都需要执行其他操作,则可以在第一次触发Activated()
事件时将bool
设置为true,这样就不会在后续激活时滚动,但仍可以执行其他操作需要做。
此外,如果TextBox
位于不是SelectedTab
的选项卡上,ScrollToCarat()
将无效。因此,在滚动时至少需要将其设为选定的选项卡。如果表单在执行此操作时闪烁,则可以将代码包装在YourTab.SuspendLayout();
和YourTab.ResumeLayout(false);
对中。
编辑结束
希望这可以帮助!
当文本更改时,这将滚动到文本框的末尾,但仍允许用户向上滚动
outbox.SelectionStart = outbox.Text.Length;
outbox.ScrollToEnd();
在Visual Studio Enterprise 2017上测试过
对于任何希望看到webforms实现的人来到这里,你想使用Page Request Manager的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);
这对我有用...
txtSerialLogging-> Text =“”;
txtSerialLogging-> AppendText通过(一个或多个);
我尝试了上面的所有情况,但问题是在我的情况下,文本s可以减少,增加并且还可以长时间保持静态。静态意味着,静态长度(行)但内容是不同的。
所以,当长度(线)在某些时候保持相同时,我在最后面临一线跳跃情况......
我为此使用了一个函数:
private void Log (string s) {
TB1.AppendText(Environment.NewLine + s);
TB1.ScrollToCaret();
}