2010-09-29 6 views
14

¿Cómo puedo sincronizar el desplazamiento de dos cuadros de texto multilínea en C# (WinForms)?¿Cómo puedo sincronizar el desplazamiento de dos cuadros de texto multilínea?

Cuando se desplaza hacia arriba o hacia abajo una línea en TextBox A, TextBox B también debe desplazarse hacia arriba o hacia abajo. Lo mismo al revés.

¿Esto se puede lograr sin controles personalizados?

+0

Imposible responder a menos que nos diga qué tipo de marco de GUI está utilizando. – mikerobi

+0

Simplemente por defecto WinForms. – lesderid

Respuesta

34

Sí, tendrá que crear un cuadro de texto personalizado para que pueda detectarlo desplazándose. El truco es pasar el mensaje de desplazamiento al otro cuadro de texto para que se desplace en sincronía. Esto realmente solo funciona bien cuando el otro cuadro de texto tiene aproximadamente el mismo tamaño y tiene el mismo número de líneas.

Agregue una nueva clase a su proyecto y pegue el código que se muestra a continuación. Compilar. Coloque dos de los nuevos controles desde la parte superior de la caja de herramientas en su formulario. Establezca la propiedad Buddy en el otro control en ambos. Ejecutar, escriba algo de texto en ambos y mire cómo se desplazan en sincronización a medida que arrastra la barra de desplazamiento.

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

¡Impresionante, gracias! – lesderid

+1

¡Esto es un milagro! –

+0

@ Hans Passant: quería lograr similares, pero en el caso de dos vistas de lista. Intenté usar este código pero no funciona. ¿Debo agregar algo en esto? –

8

Puede cambiar esta línea:

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

a esto:

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

y apoyará el desplazamiento con la rueda del ratón también.

+0

gracias por esto, esto fue increíblemente útil – eruciform

+0

Desafortunadamente, aunque esto parece funcionar, el desplazamiento no se sincroniza con la rueda del mouse y el cuadro de texto principal se desplaza más rápido que el amigo. – SurfingSanta

+0

¿Qué tal cuando arrastra la barra deslizante y el botón izquierdo del mouse presionado mueve la tapa hacia arriba y hacia abajo, la vista de la lista de amigos no reacciona al desplazamiento? –

2

La solución de Hans Passant funcionaba como un amuleto, pero necesitaba un RichTextBox con barras de desplazamiento horizontales y verticales. Si extiendes un RichTextBox en lugar de un TextBox, necesitarás cambiar la propiedad ScrollBars en consecuencia (utilicé RichTextBoxScrollBars.Both).

Si también desea sincronizar el desplazamiento horizontal, busque (m.Msg == 0x115) || (m.Msg == 0x114).

3

La solución de Hans Passant fue increíble. Sin embargo, necesitaba sincronizar tres cuadros de texto, no solo dos.

Así que lo modifiqué un poco, pero toda la credibilidad debería ir a Hans, no hay forma de que incluso me hubiera acercado sin su trabajo, pensé que lo publicaría de nuevo aquí en caso de que otros necesiten lo mismo.

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

Luego, en la 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

Esto es lo que finalmente me ayudó a fijar la sincronización de múltiples cuadros de texto utilizando la rueda del ratón.

Lo he basado en un muy útil ejemplo de 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); 
} 
Cuestiones relacionadas