.Multilineプロパティをtrueに設定したテキストボックスがあります。定期的に、新しい行のテキストを追加しています。新しい行が追加されるたびに、テキストボックスを一番下のエントリ(最新のエントリ)まで自動的にスクロールしたいと思います。どうすればこれを達成できますか?
.Multilineプロパティをtrueに設定したテキストボックスがあります。定期的に、新しい行のテキストを追加しています。新しい行が追加されるたびに、テキストボックスを一番下のエントリ(最新のエントリ)まで自動的にスクロールしたいと思います。どうすればこれを達成できますか?
回答:
定期的に、新しい行のテキストを追加しています。新しい行が追加されるたびに、テキストボックスを一番下のエントリ(最新のエントリ)まで自動的にスクロールしたいと思います。
を使用するTextBox.AppendText(string text)
と、新しく追加されたテキストの最後まで自動的にスクロールします。ループで呼び出す場合、ちらつきのスクロールバーを回避します。
また、.Text
プロパティに連結するよりも桁違いに高速です。それはあなたがそれを呼ぶ頻度に依存するかもしれませんが; 私はタイトなループでテストしていました。
これは、テキストボックスが表示される前に呼び出された場合、またはテキストボックスが表示されない場合(TabPanelの別のタブなど)はスクロールしません。自動スクロールしないTextBox.AppendText()を参照してください。これは、ユーザーがテキストボックスを表示できないときに自動スクロールが必要かどうかによって、重要な場合とそうでない場合があります。
この場合、他の回答からの代替方法も機能しないようです。それを回避する1つの方法は、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 += ....
D:との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);
ペアでラップできます。
編集の終わり
お役に立てれば!
これは、テキストが変更されたときにテキストボックスの最後までスクロールしますが、ユーザーは上にスクロールできます
outbox.SelectionStart = outbox.Text.Length;
outbox.ScrollToEnd();
Visual Studio Enterprise 2017でテスト済み
Webフォームの実装を期待してここに着陸する他の人は、ページリクエストマネージャーの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);
上記のすべてのケースを試しましたが、問題は私の場合、テキストが減少したり、増加したり、長時間静止したままになる可能性があることです。staticは、静的な長さ(行)を意味しますが、内容が異なります。
それで、長さ(行)が同じままである最後の行ジャンプの状況に直面していました...