2009-07-01 4 views
22

Sto usando winforms e aggiorno una casella di testo una volta ogni tanto (mostrando messaggi). tuttavia, quando il testo raggiunge la fine della scatola produce barre di scorrimento e non so come scorrere verso il basso. L'unica cosa che vedo è ScrollToCaret, ma Caret è all'inizio del testo. Qual è il comando per scorrere?Come scorrere verso il basso in una casella di testo per codice in C#

+0

Sarebbe utile: rilevare quando textarea di scorrimento ha raggiunto il fondo pulsante per abilitare. Voglio visualizzare un accordo di licenza in un'area di testo a scorrimento e rilevare quando l'utente ha spostato fino alla fine dell'area di testo, quindi attivare il pulsante di invio. C'è un modo per farlo? – Kiquenet

risposta

32

Si può fare questo facendo uso di una funzione chiamata ScrollToCaret. È necessario prima impostare la posizione del punto di inserimento fino alla fine della casella di testo, quindi è possibile scorrere ad essa. Ecco come fare:

 //move the caret to the end of the text 
     textBox.SelectionStart = textBox.TextLength; 
     //scroll to the caret 
     textBox.ScrollToCaret(); 
+1

ScrollToCaret() funziona solo se la casella di testo in questione è attiva. Vedi sotto per una soluzione che gestisce anche la casella di testo che non ha il focus: http: // StackOverflow.it/questions/1069497/2585177 # 2585177 – Nailuj

+0

Sicuramente se questo è davvero il caso, allora una chiamata a TextBox.Focus in anticipo funzionerebbe. Non c'è bisogno di usare Pinvoke. –

+0

Sì, è possibile. Ma ci potrebbero benissimo essere casi in cui ti piacerebbe mantenere l'attenzione da qualche altra parte nel tuo modulo durante lo scorrimento del TextBox. E se questo è il caso, dovresti implementare una logica extra per "ri-focalizzare" l'elemento corretto dopo averlo fatto. Ma ora sono solo schizzinoso;) – Nailuj

4

è necessario impostare il vostro punto di inserimento alla fine del testo:

textBox1.Text += "your new text"; 
textBox1.Select(textBox1.Text.Length - 1, 0); 
textBox1.ScrollToCaret(); 
0

È possibile utilizzare il SetScrollPos API:

[DllImport("user32.dll")] 
static extern int SetScrollPos(IntPtr hWnd, int nBar, int nPos, bool bRedraw); 

[DllImport("user32.dll")] 
static extern bool GetScrollRange(IntPtr hWnd, int nBar, out int lpMinPos, out int lpMaxPos); 

const int SB_HORZ = 0; 
const int SB_VERT = 1; 
const int SB_CTL = 2; 


... 

void ScrollToBottom(Control ctl) 
{ 
    int min; 
    int max; 
    if (GetScrollRange(ctl.Handle, SB_VERT, out min, out max)) 
    { 
     SetScrollPos(ctl.Handle, SB_VERT, max, true); 
    } 
} 

(non testato)

+0

Questo non scorre acutamente la casella di testo, ma modifica semplicemente la posizione del piccolo pulsante sulla barra di scorrimento. –

14

Se si utilizza il metodo AppendText() della casella di testo, il testo sarà aggiunto in fondo a qualsiasi testo esistente e il controllo scorrerà per visualizzarlo.

+1

Funziona anche quando la casella di testo non ha il focus. –

26

Questa è una domanda un po 'vecchia, ma nessuna delle risposte suggerite ha funzionato per me (ScrollToCaret() funziona solo quando il controllo TextBox è attivo). Quindi, nel caso in cui più dovrebbe essere alla ricerca di questo ad un certo punto, ho pensato di condividere quello che ho trovato essere la soluzione:

public class Utils 
{ 
    [DllImport("user32.dll", CharSet = CharSet.Auto)] 
    private static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, 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(TextBox tb) 
    { 
     SendMessage(tb.Handle, WM_VSCROLL, (IntPtr)SB_BOTTOM, IntPtr.Zero); 
    } 
} 

di credito per la soluzione dovrebbe andare a questo post a bytes.com: http://bytes.com/topic/c-sharp/answers/248500-scroll-bottom-textbox#post1005377

+2

Funziona !!!!! Ho trovato un messaggio di miliardi che diceva di usare ScrollToCaret che ovviamente non funziona se il controllo non ha il focus. Funziona! –

+1

Vorrei avere 100 voti positivi da dare. Questo e spettacolare!! –

+0

Funziona ma il problema è che la barra di scorrimento salta su e giù, non un aspetto user friendly !!! (stesso problema o anche peggio con quella ScrollToCarret soloution) –

2

C# Usa scorrere su/giù da Windows API (user32.dll)

In primo luogo, dobbiamo definire un valore costante:

const int EM_LINESCROLL = 0x00B6; 
const int SB_HORZ = 0; 
const int SB_VERT = 1; 

Poi, dobbiamo dichiarare due metodi esterni di user32.dll:

[DllImport("user32.dll")] 
static extern int SetScrollPos(IntPtr hWnd, int nBar, int nPos, bool bRedraw); 

[DllImport("user32.dll")] 
static extern int SendMessage(IntPtr hWnd, int wMsg, int wParam, int lParam); 

Infine, utilizzare questi metodi per fare la cosa vera:

SetScrollPos(myTextBox.Handle,SB_VERT,myTextBox.Lines.Length-1,true); 
SendMessage(myTextBox.Handle,EM_LINESCROLL,0,myTextBox.Lines.Length-1); 

Fatto! Semplice e facile! Provato! original post

0

Dopo aver cercato e mai trovare una soluzione legittima che funziona con e senza messa a fuoco così come orizzontalmente e verticalmente, mi sono imbattuto in una soluzione di API che funziona (almeno per la mia piattaforma - Win7/.Net4 WinForms).

using System; 
using System.Runtime.InteropServices; 

namespace WindowsNative 
{ 
    /// <summary> 
    /// Provides scroll commands for things like Multiline Textboxes, UserControls, etc. 
    /// </summary> 
    public static class ScrollAPIs 
    { 
     [DllImport("user32.dll")] 
     internal static extern int GetScrollPos(IntPtr hWnd, int nBar); 

     [DllImport("user32.dll")] 
     internal static extern int SetScrollPos(IntPtr hWnd, int nBar, int nPos, bool bRedraw); 

     [DllImport("user32.dll")] 
     internal static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam); 

     public enum ScrollbarDirection 
     { 
      Horizontal = 0, 
      Vertical = 1, 
     } 

     private enum Messages 
     { 
      WM_HSCROLL = 0x0114, 
      WM_VSCROLL = 0x0115 
     } 

     public static int GetScrollPosition(IntPtr hWnd, ScrollbarDirection direction) 
     { 
      return GetScrollPos(hWnd, (int)direction); 
     } 

     public static void GetScrollPosition(IntPtr hWnd, out int horizontalPosition, out int verticalPosition) 
     { 
      horizontalPosition = GetScrollPos(hWnd, (int)ScrollbarDirection.Horizontal); 
      verticalPosition = GetScrollPos(hWnd, (int)ScrollbarDirection.Vertical); 
     } 

     public static void SetScrollPosition(IntPtr hwnd, int hozizontalPosition, int verticalPosition) 
     { 
      SetScrollPosition(hwnd, ScrollbarDirection.Horizontal, hozizontalPosition); 
      SetScrollPosition(hwnd, ScrollbarDirection.Vertical, verticalPosition); 
     } 

     public static void SetScrollPosition(IntPtr hwnd, ScrollbarDirection direction, int position) 
     { 
      //move the scroll bar 
      SetScrollPos(hwnd, (int)direction, position, true); 

      //convert the position to the windows message equivalent 
      IntPtr msgPosition = new IntPtr((position << 16) + 4); 
      Messages msg = (direction == ScrollbarDirection.Horizontal) ? Messages.WM_HSCROLL : Messages.WM_VSCROLL; 
      SendMessage(hwnd, (int)msg, msgPosition, IntPtr.Zero); 
     } 
    } 
} 

Con una casella di testo multilinea (tbx_main) utilizzare come:

 int horzPos, vertPos; 
     ScrollAPIs.GetScrollPosition(tbx_main.Handle, out horzPos, out vertPos); 

     //make your changes 
     //something like the following where m_buffer is a string[] 
     tbx_main.Text = string.Join(Environment.NewLine, m_buffer); 

     tbx_main.SelectionStart = 0; 
     tbx_main.SelectionLength = 0; 

     ScrollAPIs.SetScrollPosition(tbx_main.Handle, horzPos, vertPos);