我有一个.Multiline属性设置为true的文本框。我会定期添加新的文本行。我希望文本框在添加新行时自动滚动到最底部的条目(最新条目)。我该如何完成?
我有一个.Multiline属性设置为true的文本框。我会定期添加新的文本行。我希望文本框在添加新行时自动滚动到最底部的条目(最新条目)。我该如何完成?
Answers:
我会定期添加新的文本行。我希望文本框在添加新行时自动滚动到最底部的条目(最新条目)。
如果使用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;
但是应该没有理由手动进行。
(如果您自己进行反编译,您会发现它使用了一些可能更有效的内部方法,并且似乎是次要的特殊情况。)
tb.Text += ....
和WndProc一起
您可以使用以下代码段:
myTextBox.SelectionStart = myTextBox.Text.Length;
myTextBox.ScrollToCaret();
它将自动滚动到末尾。
似乎接口在.NET 4.0中已更改。通过以下方法可以实现上述所有目的。正如Tommy Engebretsen所建议的那样,将其放在TextChanged事件处理程序中会使它自动执行。
textBox1.ScrollToEnd();
TextBoxBase
类中。这种方法不存在,也不会在的WinForms,他们的工作类继承的命名空间(组装的WinForms)。System.Windows.Controls.Primitives
PresentationFramework
TextBox
TextBoxBase
System.Windows.Forms
System.Windows.Forms
ScrollToEnd()
可能是非常糟糕的表现。在我的应用程序中,它占了分析时间的50%以上。
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);
如果您在每次激活表单时还需要执行其他操作,则可以bool
在第一次Activated()
触发事件时将a设置为true ,这样您就无需滚动后续的激活操作,但仍然可以执行其他操作做。
另外,如果您TextBox
的标签不在上SelectedTab
,ScrollToCarat()
则不会起作用。因此,滚动时至少需要使其成为选定的选项卡。如果执行此操作时表格闪烁,则可以将代码包装为YourTab.SuspendLayout();
和YourTab.ResumeLayout(false);
。
编辑结束
希望这可以帮助!
对于希望在此查看Webforms实现的其他人,您想使用页面请求管理器的endRequest事件处理程序(https://stackoverflow.com/a/1388170/1830512)。这是我从母版页在内容页中为文本框所做的操作,请忽略我没有为控件使用变量的事实:
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);
我尝试了上述所有情况,但问题在于我的案文可以减少,增加,并且可以长时间保持静态。静态表示,静态长度(行),但内容不同。
所以,当长度(行)有时保持不变时,我最终遇到了跳线的情况。