Comment faire défiler automatiquement vers le bas d'une boîte de texte multiligne?

j'ai une zone de texte avec la .Propriété multiligne définie à true. À intervalles réguliers, j'y ajoute de nouvelles lignes de texte. J'aimerais que la boîte de texte fasse défiler automatiquement la dernière entrée (la plus récente) chaque fois qu'une nouvelle ligne est ajoutée. Comment puis-je accomplir cela?

239
demandé sur GWLlosa 2009-05-22 18:57:54

11 réponses

à intervalles réguliers, j'y ajoute de nouvelles lignes de texte. J'aimerais que la boîte de texte fasse défiler automatiquement la dernière entrée (la plus récente) chaque fois qu'une nouvelle ligne est ajoutée.

si vous utilisez TextBox.AppendText(string text) , il défilera automatiquement jusqu'à la fin du texte nouvellement ajouté. Il évite le scintillement scrollbar si vous l'appelez dans une boucle.

il se trouve que c'est aussi un ordre de magnitude plus rapide que la concaténation sur la propriété .Text . Bien que cela puisse dépendre de la fréquence à laquelle vous l'appelez; je testais avec une boucle serrée.


cette option ne fait pas défiler si elle est appelée avant que la zone de texte ne soit affichée, ou si la zone de texte n'est pas visible (par exemple dans un onglet différent d'un TabPanel). Voir L'Encadré .AppendText() pas le défilement automatique . Cela peut être ou ne pas être important, selon que vous require autoscroll quand l'utilisateur ne peut pas voir la boîte de texte.

il semble que la méthode alternative des autres réponses ne fonctionne pas non plus dans ce cas. Une façon de contourner cela est d'effectuer un défilement supplémentaire sur le VisibleChanged événement:

textBox.VisibleChanged += (sender, e) =>
{
    if (textBox.Visible)
    {
        textBox.SelectionStart = textBox.TextLength;
        textBox.ScrollToCaret();
    }
};

en Interne, AppendText fait quelque chose comme ceci:

textBox.Select(textBox.TextLength + 1, 0);
textBox.SelectedText = textToAppend;

Mais il devrait y avoir aucune raison de le faire manuellement.

(si vous le décompilez vous-même, vous verrez qu'il utilise des méthodes internes peut-être plus efficaces, et a ce qui semble être un cas spécial mineur.)

347
répondu Bob 2017-05-23 11:47:01

vous pouvez utiliser l'extrait de code suivant:

myTextBox.SelectionStart = myTextBox.Text.Length;
myTextBox.ScrollToCaret();

qui se dérouleront automatiquement jusqu'à la fin.

137
répondu GWLlosa 2009-05-22 14:58:50

il semble que l'interface ait changé en .NET 4.0. Il y a la méthode qui réalise tout ce qui précède. Comme Tommy Engebretsen l'a suggéré, le mettre dans un gestionnaire D'événements TextChanged le rend automatique.

textBox1.ScrollToEnd();
35
répondu JohnDRoach 2013-02-06 12:51:09

essayez d'ajouter le code suggéré à L'événement TextChanged:

private void textBox1_TextChanged(object sender, EventArgs e)
{
  textBox1.SelectionStart = textBox1.Text.Length;
  textBox1.ScrollToCaret();
}
14
répondu GWLlosa 2011-02-22 14:35:31

je devais ajouter un rafraîchissement:

textBox1.SelectionStart = textBox1.Text.Length;
textBox1.ScrollToCaret();
textBox1.Refresh();
8
répondu h4nd 2011-11-17 01:35:39
textBox1.Focus()
textBox1.SelectionStart = textBox1.Text.Length;
textBox1.ScrollToCaret();

n'a pas fonctionné pour moi (Windows 8.1, quelle que soit la raison).

Et puisque je suis toujours sur .NET 2.0, Je ne peux pas utiliser ScrollToEnd.



Mais cela fonctionne:

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
7
répondu Stefan Steiger 2015-04-15 09:13:13

j'ai trouvé une différence simple qui n'a pas été abordée dans ce fil.

si vous faites tous les appels ScrollToCarat() dans le cadre de l'événement Load() de votre formulaire, cela ne fonctionne pas. Je viens d'ajouter mon appel ScrollToCarat() à l'événement Activated() de mon formulaire, et ça marche très bien.

Modifier

il est important de ne faire ce défilement que la première fois que l'événement Activated du formulaire est déclenché (pas sur les activations suivantes), ou il fera défiler chaque fois que votre forme est activée, ce qui est quelque chose que vous ne voulez probablement pas.

donc si vous ne faites que piéger l'événement Activated() pour faire défiler votre texte lorsque votre programme se charge, alors vous pouvez simplement vous désabonner de l'événement à l'intérieur du gestionnaire d'événement lui-même, thusly:

Activated -= new System.EventHandler(this.Form1_Activated);

Si vous avez d'autres choses que vous devez faire à chaque fois que votre formulaire est activé, vous pouvez définir un bool à true la première fois que votre événement Activated() est déclenché, donc vous ne faites pas défiler sur les activations suivantes, mais vous pouvez toujours faire les autres choses que vous devez faire.

Aussi, si votre TextBox est sur un onglet qui n'est pas le SelectedTab , ScrollToCarat() n'aura aucun effet. Donc, vous avez besoin au moins le faire l'onglet sélectionné pendant que vous faites défiler. Vous pouvez envelopper le code dans une paire YourTab.SuspendLayout(); et YourTab.ResumeLayout(false); si votre forme clignote lorsque vous faites cela.

fin de l'édition

Espérons que cette aide!

2
répondu Pete 2015-04-24 01:36:23

cela fera défiler jusqu'à la fin de la zone de texte lorsque le texte est modifié, mais permet tout de même à l'utilisateur de faire défiler vers le haut

outbox.SelectionStart = outbox.Text.Length;
outbox.ScrollToEnd();

testé sur Visual Studio Enterprise 2017

1
répondu Eric Shreve 2017-04-16 16:29:23

pour quiconque atterrissant ici s'attendant à voir une implémentation de webforms, vous voulez utiliser le gestionnaire d'événements endRequest du Gestionnaire de requêtes de Page ( https://stackoverflow.com/a/1388170/1830512 ). Voici ce que j'ai fait pour ma boîte de texte dans une Page de contenu à partir d'une page maître, s'il vous plaît ignorer le fait que je n'ai pas utilisé une variable pour le contrôle:

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);
1
répondu Greg Greenleaf 2018-02-14 19:35:02

ça n'a marché que pour moi...

txtSerialLogging->Texte = "";

txtSerialLogging- > AppendText (s);

j'ai essayé tous les cas ci-dessus, mais le problème est dans mon cas des textes peuvent diminuer, augmenter et peuvent également rester statique pendant une longue période. statique signifie , statique longueur(lignes), mais le contenu est différent.

donc, je faisais face à une situation de saut de ligne à la fin quand la longueur (les lignes) reste le même pour quelques temps...

0
répondu TooGeeky 2014-10-10 09:51:05

j'utilise une fonction pour cela:

private void Log (string s) {
    TB1.AppendText(Environment.NewLine + s);
    TB1.ScrollToCaret();
}
0
répondu DMike92 2014-12-18 18:08:28