2010-09-29 15 views
14

Come posso sincronizzare lo scorrimento di due caselle di testo multilinea in C# (WinForms)?Come posso sincronizzare lo scorrimento di due caselle di testo multilinea?

Quando si scorre su/giù una riga in TextBox A, TextBox B deve scorrere anche su/giù. Lo stesso al contrario.

È realizzabile senza controlli personalizzati?

+0

Impossibile rispondere a meno che non ci dica quale tipo di framework GUI si sta utilizzando. – mikerobi

+0

Solo default WinForms. – lesderid

risposta

34

Sì, sarà necessario creare una casella di testo personalizzata in modo da poter rilevare lo scorrimento. Il trucco è passare il messaggio di scorrimento all'altra casella di testo in modo che scorra in sincronia. Questo funziona davvero bene solo quando l'altra casella di testo ha all'incirca le stesse dimensioni e lo stesso numero di righe.

Aggiungi una nuova classe al tuo progetto e incolla il codice mostrato di seguito. Compilare. Rilascia due dei nuovi controlli dalla parte superiore della casella degli strumenti sul modulo. Imposta la proprietà Buddy sull'altro controllo su entrambi. Esegui, digita del testo in entrambi e guardali scorrere in sincrono mentre trascini la barra di scorrimento.

using System; 
using System.Windows.Forms; 
using System.Runtime.InteropServices; 

class SyncTextBox : TextBox { 
    public SyncTextBox() { 
     this.Multiline = true; 
     this.ScrollBars = ScrollBars.Vertical; 
    } 
    public Control Buddy { get; set; } 

    private static bool scrolling; // In case buddy tries to scroll us 
    protected override void WndProc(ref Message m) { 
     base.WndProc(ref m); 
     // Trap WM_VSCROLL message and pass to buddy 
     if (m.Msg == 0x115 && !scrolling && Buddy != null && Buddy.IsHandleCreated) { 
      scrolling = true; 
      SendMessage(Buddy.Handle, m.Msg, m.WParam, m.LParam); 
      scrolling = false; 
     } 
    } 
    [DllImport("user32.dll", CharSet = CharSet.Auto)] 
    private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp); 
} 
+1

Fantastico, grazie! – lesderid

+1

Questo è un miracolo !!!! –

+0

@Hans Passant: volevo ottenere risultati simili, ma in caso di due visualizzazioni elenco. ho provato a utilizzare questo codice ma non funziona. devo aggiungere qualcosa in questo? –

8

È possibile modificare questa linea:

if (m.Msg == 0x115) && !scrolling && Buddy != null && Buddy.IsHandleCreated) 

a questo:

if ((m.Msg == 0x115 || m.Msg==0x20a) && !scrolling && Buddy != null && Buddy.IsHandleCreated) 

e sosterrà lo scorrimento con la rotellina del mouse pure.

+0

grazie per questo, questo è stato incredibilmente utile – eruciform

+0

Sfortunatamente, anche se questo sembra funzionare, lo scorrimento non è sincronizzato con la rotellina del mouse e la casella di testo principale scorre più velocemente del compagno. – SurfingSanta

+0

Che dire di quando si trascina la diapositiva di scorrimento e si preme il pulsante sinistro del mouse per spostare la diapositiva su e giù, la vista dell'elenco amici non reagisce allo scorrimento? –

2

La soluzione di Hans Passant ha funzionato come un incantesimo ma avevo bisogno di un RichTextBox con barre di scorrimento orizzontali e verticali. Se estendi un RichTextBox invece di un TextBox, dovrai modificare di conseguenza la proprietà ScrollBars (ho utilizzato RichTextBoxScrollBars.Both).

Se si desidera sincronizzare lo scorrimento orizzontale, cercare (m.Msg == 0x115) || (m.Msg == 0x114).

3

La soluzione di Hans Passant è stata fantastica. Tuttavia avevo bisogno di sincronizzare tre caselle di testo non solo due.

Quindi l'ho modificato un po '- ma tutta l'affidabilità dovrebbe andare ad Hans, non c'è modo che mi sarei avvicinato senza il suo lavoro - ho pensato di riporlo qui nel caso in cui gli altri avessero bisogno dello stesso.

classe SyncBox:

using System; 
using System.Windows.Forms; 
using System.Runtime.InteropServices; 

class SyncTextBox : TextBox 
{ 
    public SyncTextBox() 
    { 
     this.Multiline = true; 
     this.ScrollBars = ScrollBars.Vertical; 
    } 

    public Control[] Buddies { get; set; } 

    private static bool scrolling; // In case buddy tries to scroll us 
    protected override void WndProc(ref Message m) 
    { 
     base.WndProc(ref m); 
     // Trap WM_VSCROLL message and pass to buddy 
     if (Buddies != null) 
     { 
      foreach (Control ctr in Buddies) 
      { 
       if (ctr != this) 
       { 
        if ((m.Msg == 0x115 || m.Msg == 0x20a) && !scrolling && ctr.IsHandleCreated) 
        { 
         scrolling = true; 
         SendMessage(ctr.Handle, m.Msg, m.WParam, m.LParam); 
         scrolling = false; 
        } 
       } 
      } 
     } 
    } 
    [DllImport("user32.dll", CharSet = CharSet.Auto)] 
    private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp); 
} 

Poi nella forma initilizer:

// add the required controls into scroll sync 
Control[] syncedCtrls = new Control[] { ctrl1, ctrl2, ..., ctrln }; 
foreach (SyncTextBox ctr in syncedCtrls) 
{ 
    ctr.Buddies = syncedCtrls; 
} 
0

Ecco ciò che alla fine mi ha aiutato a risolvere la sincronizzazione di più caselle di testo usando la rotellina del mouse.

L'ho basato sull'esempio molto utile di Hans.

int WM_MOUSEWHEEL = 0x20a; // or 522 
int WM_VSCROLL  = 0x115; // or 277 

protected override void WndProc(ref Message m) 
{ 
     //Trap WM_VSCROLL and WM_MOUSEWHEEL message and pass to buddy 
     if (Buddies != null) 
     { 

      if (m.Msg == WM_MOUSEWHEEL) //mouse wheel 
      { 

       if ((int)m.WParam < 0) //mouse wheel scrolls down 
        SendMessage(this.Handle, (int)0x0115, new IntPtr(1), new IntPtr(0)); //WParam: 1- scroll down, 0- scroll up 
       else if ((int)m.WParam > 0) 
        SendMessage(this.Handle, (int)0x0115, new IntPtr(0), new IntPtr(0)); 



       return; //prevent base.WndProc() from messing synchronization up 
      } 
      else if (m.Msg == WM_VSCROLL) 
      { 
       foreach (Control ctr in Buddies) 
       { 
        if (ctr != this && !scrolling && ctr != null && ctr.IsHandleCreated) 
        { 
         scrolling = true; 
         SendMessage(ctr.Handle, m.Msg, m.WParam, m.LParam); 
         scrolling = false; 
        } 

       } 

      } 
     } 

    //do the usual 
    base.WndProc(ref m); 
} 
Problemi correlati