2009-12-01 10 views
15

Nel modulo della mia domanda, ho due oggetti RichTextBox. Entrambi avranno sempre lo stesso numero di righe di testo. Mi piacerebbe "sincronizzare" lo scorrimento verticale tra questi due, in modo che quando l'utente cambia la posizione di scorrimento verticale su uno, l'altro scorre lo stesso importo. Come potrei andare a fare questo?C#: sincronizza la posizione di scorrimento di due RichTextBox?

risposta

15

Ho fatto questo per un piccolo progetto qualche tempo fa, ed ecco la soluzione semplicistica che ho trovato.

Creare un nuovo controllo per subclassing RichTextBox:

public class SynchronizedScrollRichTextBox : System.Windows.Forms.RichTextBox 
    { 
     public event vScrollEventHandler vScroll; 
     public delegate void vScrollEventHandler(System.Windows.Forms.Message message); 

     public const int WM_VSCROLL = 0x115; 

     protected override void WndProc(ref System.Windows.Forms.Message msg) { 
      if (msg.Msg == WM_VSCROLL) { 
       if (vScroll != null) { 
        vScroll(msg); 
       } 
      } 
      base.WndProc(ref msg); 
     } 

     public void PubWndProc(ref System.Windows.Forms.Message msg) { 
      base.WndProc(ref msg); 
     } 
    }  

Aggiungere il nuovo controllo al form e per ogni controllo di avvisare esplicitamente le altre istanze del controllo che la sua posizione VScroll è cambiata. Somthing come questo:

private void scrollSyncTxtBox1_vScroll(Message msg) { 
    msg.HWnd = scrollSyncTxtBox2.Handle; 
    scrollSyncTxtBox2.PubWndProc(ref msg); 
} 

penso che questo codice ha problemi se tutti i controlli 'collegate' non hanno lo stesso numero di righe visualizzabili.

+0

Questo metodo funziona correttamente per lo scorrimento spostando la barra di scorrimento. Ma le barre di scorrimento non sono sincronizzate quando (1) scorre con la rotellina del mouse (2) scorrendo con i tasti 'pagina giù' o' pagina su' - scorrendo premendo i tasti freccia – twnaing

+0

@Jay riggs 'System.Windows.Forms.RichTextBox' non contiene una definizione per "PubWndProc" e nessun metodo di estensione "PubWndProc" che accetta un primo argomento di tipo "System.Windows.Forms.RichTextBox" potrebbe essere trovato (ti manca una direttiva using o un riferimento di assembly?) – Pomster

18

Grazie Jay per la risposta; dopo un po 'di ricerche ho trovato anche il metodo descritto here. Lo traccerò qui sotto per chiunque sia interessato.


In primo luogo, dichiarare le seguenti enumerazioni:

public enum ScrollBarType : uint { 
    SbHorz = 0, 
    SbVert = 1, 
    SbCtl = 2, 
    SbBoth = 3 
} 

public enum Message : uint { 
    WM_VSCROLL = 0x0115 
} 

public enum ScrollBarCommands : uint { 
    SB_THUMBPOSITION = 4 
} 

Quindi, aggiungere i riferimenti esterni per GetScrollPos e SendMessage.

[DllImport("User32.dll")] 
public extern static int GetScrollPos(IntPtr hWnd, int nBar); 

[DllImport("User32.dll")] 
public extern static int SendMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam); 

Infine, aggiungere un gestore eventi per l'evento VScroll della appropriata RichTextBox:

private void myRichTextBox1_VScroll(object sender, EventArgs e) 
{ 
    int nPos = GetScrollPos(richTextBox1.Handle, (int)ScrollBarType.SbVert); 
    nPos <<= 16; 
    uint wParam = (uint)ScrollBarCommands.SB_THUMBPOSITION | (uint)nPos; 
    SendMessage(richTextBox2.Handle, (int)Message.WM_VSCROLL, new IntPtr(wParam), new IntPtr(0)); 
} 

In questo caso, la posizione di scorrimento verticale richTextBox2 s' sarà sincronizzato con richTextBox1.

+0

Sommario grande . Ho risparmiato molto tempo. Grazie! –

+1

quale sarebbe il codice esadecimale per WM_HSCROLL? – Logerfo

1

Una variante dell'approccio di sottoclasse di Jay può essere trovato nel post di Joseph Kingry qui: Synchronizing Multiline Textbox Positions in C#. L'approccio di Joseph include anche sottoclassi, ma non richiede un gestore di eventi _VScroll. Ho usato questo approccio per creare un legame a 3 vie tra 3 caselle e aggiunto WM_HSCROLL.

3

[Visual Studio C# 2010 Express, v10.0.30319 in un'installazione 7 a 64 bit di Windows]

ho usato la soluzione di Donut postato sopra, ma ha trovato un problema quando si scorre fino alla fine della RichTextBoxes che contengono molte linee.

Se il risultato di GetScrollPos() è >0x7FFF allora quando nPos viene spostato, viene impostato il bit superiore. La creazione di IntPtr con la variabile wParam risultante avrà quindi esito negativo con un OverflowException. Si può facilmente verificare con il seguente (la seconda linea non riuscirà):

IntPtr ip = new IntPtr(0x7FFF0000); 
    IntPtr ip2 = new IntPtr(0x80000000); 

Una versione di SendMessage() che utilizza UIntPtr sembrerebbe essere una soluzione, ma non ho potuto ottenere quello per funzionare.Così, ho utilizzare il seguente:

[DllImport("User32.dll")] 
    public extern static int SendMessage(IntPtr hWnd, uint msg, UInt32 wParam, UInt32 lParam); 

Questo dovrebbe essere buono fino a 0xffff, ma vorrei riuscire dopo. Non ho ancora riscontrato un risultato >0xffff da GetScrollPos() e si presume che User32.dll sia improbabile che disponga di una versione a 64 bit di SendCommand(), ma qualsiasi soluzione a tale problema sarebbe molto apprezzata.

Problemi correlati