.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;
しかしそれを手動で行う理由はないはずです。
(自分で逆コンパイルした場合、おそらくもっと効率的な内部メソッドが使用され、マイナーな特別なケースと思われるものがあります。)
次のコードスニペットを使用できます。
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);
私は上記のすべてのケースを試しましたが、問題は私のケースではテキストが減少し、増加し、そしてまた長い間静的なままでいることです。静的な意味、静的な長さ(行)が内容が異なります。
それで、私は長さ(ライン)が何度か同じままであるときに最後に1ラインジャンプ状況に直面していました...
これには関数を使います。
private void Log (string s) {
TB1.AppendText(Environment.NewLine + s);
TB1.ScrollToCaret();
}