Çok satırlı metin kutusunun altına otomatik olarak nasıl geçebilirim?


296

.Multiline özelliği true olarak ayarlanmış bir metin kutusu var. Düzenli aralıklarla, ona yeni metin satırları ekliyorum. Yeni bir satır eklendiğinde metin kutusunun otomatik olarak en alt girişe (en yenisi) kaymasını istiyorum. Bunu nasıl başarabilirim?


6
Burada cevabı aradım, bulamadım, bu yüzden anladım, gelecekteki kullanıcılar için buraya koyacağımı ya da belki başka birinin daha iyi bir yaklaşımı olduğunu düşündüm.
GWLlosa

2
Tüm bu süslü pantolon yeni .NET yöntemlerine sahip olmayan VBA'da aynı şeyi yapmam gerekiyordu. Gelecekte google-fu için ek bilgi şudur: TextBox1.Text = TextBox1.Text & "neyse"; TextBox1.SelStart = Len (TextBox1.Text); TextBox1.SetFocus; ... ve sonra bir .SetFocus, daha önce hangi odağın odaklandığına geri döner. TextBox1'e odaklanmadan, ne yaparsam yapayım kaydırma çubuklarını asla güncellemez.
Gordon Süpürgesi

1
@GordonBroom Whelp, bu sayede şimdi "kod snippet'lerini" "büyüler" olarak adlandırmaya başlayacağım. İyi iş. : D
Sidney

Yanıtlar:


425

Düzenli aralıklarla, ona yeni metin satırları ekliyorum. Yeni bir satır eklendiğinde metin kutusunun otomatik olarak en alt girişe (en yenisi) kaydırmasını istiyorum.

Kullanırsanız TextBox.AppendText(string text), otomatik olarak yeni eklenen metnin sonuna kayar. Bir döngü içinde çağırıyorsanız, titreyen kaydırma çubuğunu önler.

Ayrıca, .Textmülk üzerinde birleştirmekten daha hızlı bir büyüklük sırası olur . Bu, ne sıklıkta aradığınıza bağlı olsa da; Sıkı bir döngü ile test yapıyordum.


Metin kutusu gösterilmeden önce çağrılırsa veya metin kutusu başka bir şekilde görünmezse (örneğin, bir TabPanel'in farklı bir sekmesinde) kaydırma yapmaz. Otomatik kaydırma yapmadan bkz. TextBox.AppendText () yöntemi . Kullanıcı metin kutusunu göremediğinde otomatik kaydırmaya ihtiyacınız olup olmamasına bağlı olarak bu önemli olabilir veya olmayabilir.

Öyle görünüyor ki diğer cevaplardan alternatif yöntem de bu durumda işe yaramıyor. Bunun bir yolu, VisibleChangedetkinlik üzerinde ek kaydırma yapmaktır :

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

Dahili olarak, AppendText böyle bir şey yapar:

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

Ancak bunu manuel olarak yapmak için hiçbir neden olmamalıdır.

(Kendiniz koda dönüştürürseniz, muhtemelen daha verimli dahili yöntemler kullandığını ve küçük bir özel durum gibi göründüğünü göreceksiniz.)


7
Bu yöntem çok daha hızlı ve pürüzsüz. Kaydırma çubuğunun `` titremesi '' yoktur (bu, hızlı bir şekilde art arda birçok çağrı yaparken daha belirgindir).
TallGuy

3
Bu çok daha iyi bir çözüm.
Jeff

3
tb.Text += ....WndProc ve marshals ile yapmaya çalışıyorum Kendimi aptal hissediyorum: D
Saeid Yazdani

3
Textarea'nın da odaklanması gerekiyor, bunu ilk yaptığımda kaydırma yapmadığı için odaklanmadı.
Qwerty01

3
AppendText otomatik olarak ReadOnly TextBox'ımı kaydırmadı ancak TextBox.ScrollToEnd () ekledi; AppendText çağrısından sonra hile yaptı.
Brandon Barkley

143

Aşağıdaki kod snippet'ini kullanabilirsiniz:

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

otomatik olarak sonuna kadar kaydırır.


5
Burada cevabı aradım, bulamadım, bu yüzden anladım, gelecekteki kullanıcılar için buraya koyacağımı ya da belki başka birinin daha iyi bir yaklaşımı olduğunu düşündüm.
GWLlosa

4
Bu o zaman en iyi cevap olabilir, ama şimdi Bob'un cevabı OP'nin sorununa daha iyi bir çözüm olduğunu düşünüyorum.
tomsv

38

.NET 4.0'da arabirim değişmiş gibi görünüyor . Yukarıdakilerin tümünü gerçekleştiren aşağıdaki yöntem vardır. Tommy Engebretsen'in önerdiği gibi, bunu TextChanged olay işleyicisine koymak otomatik hale getirir.

textBox1.ScrollToEnd();

21
Bu yöntemin ad alanında ( assembly, WPF) TextBoxBasesınıfta olduğunu unutmayın . Bu yöntem mevcut değil ve WinForms, çalışma olmaz gelmez sınıf devralır dan içinde ad ( montaj, WinForms). System.Windows.Controls.PrimitivesPresentationFrameworkTextBoxTextBoxBaseSystem.Windows.FormsSystem.Windows.Forms
Bob

1
ScrollToEnd()Çok kötü performans gösterebileceğini unutmayın . Benim app profilleme süresinin% 50'den fazla sorumluydu.
17'de ergohack

16

Önerilen kodu TextChanged olayına eklemeyi deneyin:

private void textBox1_TextChanged(object sender, EventArgs e)
{
  textBox1.SelectionStart = textBox1.Text.Length;
  textBox1.ScrollToCaret();
}

10
textBox1.Focus()
textBox1.SelectionStart = textBox1.Text.Length;
textBox1.ScrollToCaret();

benim için çalışmadı (nedeni ne olursa olsun Windows 8.1).
Ve hala .NET 2.0'da olduğum için ScrollToEnd kullanamıyorum.

Ama bu işe yarıyor:

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

Windows 10 ile aynı sorunu yaşadık, geçici çözümünüz burada da iyi çalışıyor.
Hannes

Hiçbiri benim için çalışmıyor, ama bu. Tanrı ruhunu korusun
Emirhan Özlen

9

Bir yenileme eklemek gerekiyordu:

textBox1.SelectionStart = textBox1.Text.Length;
textBox1.ScrollToCaret();
textBox1.Refresh();

4

Bu iş parçacığında ele alınmamış basit bir fark buldum.

Tüm ScrollToCarat()aramaları formunuzun Load()etkinliğinin bir parçası olarak yapıyorsanız , çalışmaz. ScrollToCarat()Çağrılarımı Activated()formumun etkinliğine ekledim ve iyi çalışıyor.

Düzenle

Bu kaydırmanın yalnızca formun Activatedetkinliği ilk başlatıldığında (sonraki aktivasyonlarda değil) yapılması önemlidir, yoksa her Formunuz etkinleştirildiğinde zaman hangi muhtemelen istemiyorum şeydir.

Dolayısıyla, yalnızca Activated()programınız yüklendiğinde metninizi kaydırmak için etkinliği yakalarsanız, etkinlik işleyicisinin içindeki etkinliğin aboneliğini iptal edebilirsiniz, böylece:

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

Formunuz her etkinleştirildiğinde yapmanız gereken başka şeyler varsa bool, ilk defaActivated() etkinliğiniz ; yapmak.

Ayrıca, sizin TextBoxolmayan bir sekmedeyse SelectedTab, ScrollToCarat()bunun hiçbir etkisi olmaz. Bu nedenle, kaydırma yaparken en azından seçili sekmeyi yapmanız gerekir. Bunu yaptığınızda formunuz titriyorsa , kodu a YourTab.SuspendLayout();ve YourTab.ResumeLayout(false);eşleştirebilirsiniz.

Düzenleme sonu

Bu yardımcı olur umarım!


1

Bu, metin değiştirildiğinde metin kutusunun sonuna kaydırılır, ancak yine de kullanıcının yukarı kaydırmasına izin verir

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

Visual Studio Enterprise 2017'de test edildi


1

Buraya bir web formu uygulaması görmeyi bekleyen herkes için Sayfa İsteği Yöneticisi'nin endRequest olay işleyicisini ( https://stackoverflow.com/a/1388170/1830512 ) kullanmak istersiniz . Bir Ana Sayfadan bir İçerik Sayfasında TextBox'ım için yaptığım şey, lütfen kontrol için bir değişken kullanmadığım gerçeğini göz ardı edin:

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);

0

Bu sadece benim için çalıştı ...

txtSerialLogging-> Text = "";

txtSerialLogging-> appendText (s);

Yukarıdaki tüm durumları denedim, ama sorun benim durumumda metin s azalabilir, artabilir ve aynı zamanda uzun süre statik kalabilir. statik anlamına gelir, statik uzunluk (satır) ancak içerik farklıdır.

Yani, uzunluk (çizgiler) birkaç kez aynı kaldığında sonunda bir satır atlama durumu ile karşı karşıyaydım ...


Biliyorum, Bob'un cevabına benziyor, ancak belirli bir vakayı açıklıyor. VE Bob'un cevabı hakkında yorum yapamam ... Stackoverflow kuralları ile sıkışmış :(
TooGeeky

0

Bunun için bir işlev kullanın:

private void Log (string s) {
    TB1.AppendText(Environment.NewLine + s);
    TB1.ScrollToCaret();
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.