2009-12-01 10 views
15

En el formulario de mi solicitud, tengo dos objetos RichTextBox. Ambos siempre tendrán la misma cantidad de líneas de texto. Me gustaría "sincronizar" el desplazamiento vertical entre estos dos, de modo que cuando el usuario cambie la posición de desplazamiento vertical en uno, el otro recorra la misma cantidad. ¿Cómo puedo hacer esto?C#: ¿sincroniza la posición de desplazamiento de dos RichTextBoxes?

Respuesta

15

Hace un tiempo hice esto para un proyecto pequeño, y aquí está la solución simplista que encontré.

Crear un nuevo control RichTextBox por subclases:

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

Añadir el nuevo control a su forma y para cada control notificar de forma explícita las otras instancias del control que su posición VScroll ha cambiado. Algo como esto:

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

creo que este código tiene problemas si todos los controles vinculados '' no tienen el mismo número de líneas que se pueden visualizar.

+0

Este método funciona bien para desplazarse moviendo la barra de desplazamiento. Pero las barras de desplazamiento no están sincronizadas cuando (1) se desplaza con la rueda del mouse (2) desplazándose por las teclas 'page down' o' page up' - se desplaza presionando las teclas de flecha – twnaing

+0

@Jay riggs 'System.Windows.Forms.RichTextBox' no contiene una definición para 'PubWndProc' y no se puede encontrar ningún método de extensión 'PubWndProc' que acepte un primer argumento de tipo 'System.Windows.Forms.RichTextBox' (¿falta una directiva using o una referencia de ensamblado?) – Pomster

18

Gracias Jay por su respuesta; después de buscar un poco más, también encontré el método descrito here. Lo resumiré a continuación para cualquier otra persona interesada.


En primer lugar, declarar las siguientes enumeraciones:

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 
} 

A continuación, añadir referencias externas a GetScrollPos y 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); 

Por último, añadir un controlador de eventos para el VScroll caso de la apropiada 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)); 
} 

En este caso, la posición de desplazamiento vertical richTextBox2 's se sincronizará con richTextBox1.

+0

Gran resumen . Ahorré mi montón de tiempo. ¡Gracias! –

+1

¿cuál sería el código hexadecimal para WM_HSCROLL? – Logerfo

1

Una variación del enfoque de la subclase de Jay se puede encontrar en la publicación de Joseph Kingry aquí: Synchronizing Multiline Textbox Positions in C#. El enfoque de Joseph también tiene subclases, pero no requiere un manejador de eventos _VScroll. Usé ese enfoque para hacer un enlace de 3 vías entre 3 cuadros y agregué WM_HSCROLL.

3

[Visual Studio C# 2010 Express, v10.0.30319 en una instalación de Windows 7 64 bits]

He usado la solución de Donut publicado anteriormente, pero se encontró con un problema cuando se desplaza hasta el final de RichTextBoxes que contienen muchas líneas.

Si el resultado de GetScrollPos() es >0x7FFF entonces cuando se cambia nPos, se establece el bit superior. La creación del IntPtr con la variable wParam resultante fallará con un OverflowException. Se puede probar fácilmente esto con la siguiente (la segunda línea fallará):

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

Una versión de SendMessage() que utiliza UIntPtr parecería ser una solución, pero no pude conseguir que funcione.Por lo tanto, no tengo utilice la siguiente:

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

Esto debe ser bueno hasta 0xffff, pero fallaría después de eso. Todavía no he experimentado un resultado >0xffff de GetScrollPos(), y supongo que es poco probable que User32.dll tenga una versión de 64 bits de SendCommand(), pero cualquier solución a ese problema sería muy apreciada.

Cuestiones relacionadas