C #: sincroniza la posición de desplazamiento de dos RichTextBoxes?

En el formulario de mi aplicación, 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?

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

Crea un nuevo control subclasificando 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); } } 

Agregue el nuevo control a su formulario y para cada control notifique explícitamente a las otras instancias del control que su posición vScroll ha cambiado. Algo así:

 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 la misma cantidad de líneas visualizables.

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


Primero, declare 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, agregue 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 ); 

Finalmente, agregue un manejador de eventos para el evento VScroll del RichTextBox apropiado:

 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 de richTextBox1 se sincronizará con richTextBox1 .

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

He utilizado la solución de Donut publicada anteriormente, pero encontré un problema al desplazarme hasta el final de RichTextBoxes que contienen muchas líneas.

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

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

Una versión de SendMessage() que usa UIntPtr parece ser una solución, pero no pude hacer que funcione. Entonces, he usado lo siguiente:

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

Esto debería 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.

Una variación del enfoque de la subclase de Jay se puede encontrar en la publicación de Joseph Kingry aquí: Sincronización de posiciones de cuadros de texto de líneas múltiples en 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.