[英]How do I automatically scroll to the bottom of a multiline text box?
我有一個文本框,其 .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.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
我需要添加刷新:
textBox1.SelectionStart = textBox1.Text.Length;
textBox1.ScrollToCaret();
textBox1.Refresh();
我用這個。 簡單、干凈、快速!
txtTCPTxRx.AppendText(newText);
下面是我使用的實際代碼
ThreadSafe(() =>
{
string newLog = $"{DateTime.Now:HH:mm:ss:ffff->}{dLog}{Environment.NewLine}";
txtTCPTxRx.AppendText(newLog);
});
我發現了一個簡單的區別,在這個線程中沒有解決。
如果您將所有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 實現的其他人,您希望使用頁面請求管理器的 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);
關於皮特關於選項卡上的文本框的評論,我讓它工作的方式是添加
textBox1.SelectionStart = textBox1.Text.Length;
textBox1.ScrollToCaret();
到選項卡的布局事件。
這只對我有用...
txtSerialLogging->Text = "";
txtSerialLogging->AppendText(s);
我嘗試了上述所有情況,但問題是在我的情況下 text 可以減少,增加並且也可以長時間保持靜止。 靜態意味着,靜態長度(行)但內容不同。
所以,當長度(行)保持不變一段時間時,我最后面臨着一行跳躍的情況......
我為此使用了一個函數:
private void Log (string s) {
TB1.AppendText(Environment.NewLine + s);
TB1.ScrollToCaret();
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.