C #: Synchroniser la position de défilement de deux RichTextBox?

Dans le formulaire de ma demande, j’ai deux objects RichTextBox . Ils auront tous les deux toujours le même nombre de lignes de texte. Je souhaite “synchroniser” le défilement vertical entre ces deux éléments, de sorte que lorsque l’utilisateur modifie la position du défilement vertical sur l’un, l’autre défile de la même manière. Comment pourrais-je m’y prendre?

Je l’ai fait pour un petit projet il y a quelque temps, et voici la solution simpliste que j’ai trouvée.

Créez un nouveau contrôle en sous-classant 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); } } 

Ajoutez le nouveau contrôle à votre formulaire et, pour chaque contrôle, informez explicitement les autres instances du contrôle que sa position vScroll a changé. Quelque chose comme ça:

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

Je pense que ce code a des problèmes si tous les contrôles ‘liés’ n’ont pas le même nombre de lignes affichables.

Merci Jay pour votre réponse. après quelques recherches supplémentaires, j’ai également trouvé la méthode décrite ici . Je vais décrire ci-dessous pour toute autre personne intéressée.


Commencez par déclarer les énumérations suivantes:

 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 } 

Ensuite, ajoutez des références externes à GetScrollPos et 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 ); 

Enfin, ajoutez un gestionnaire d’événements pour l’événement VScroll du VScroll approprié:

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

Dans ce cas, la position de défilement vertical de richTextBox2 sera synchronisée avec richTextBox1 .

[Visual Studio C # 2010 Express, v10.0.30319 sur une installation Windows 7 64 bits]

J’ai utilisé la solution de Donut publiée ci-dessus, mais un problème est survenu lors du défilement jusqu’à la fin de RichTextBox contenant de nombreuses lignes.

Si le résultat de GetScrollPos() est >0x7FFF lorsque le nPos est décalé, le bit supérieur est défini. La création de IntPtr avec la variable wParam résultante wParam alors avec une OverflowException . Vous pouvez facilement tester ceci avec les éléments suivants (la deuxième ligne échouera):

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

Une version de SendMessage() qui utilise UIntPtr semblerait être une solution, mais je ne pouvais pas le faire fonctionner. Donc, j’ai utilisé ce qui suit:

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

Cela devrait être bon jusqu’à 0xffff , mais échouerait après cela. Je n’ai pas encore rencontré de résultat >0xffff de GetScrollPos() et GetScrollPos() suppose qu’il est peu probable que User32.dll dispose d’une version 64 bits de SendCommand() , mais toute solution à ce problème serait grandement appréciée.

Une variante de l’approche des sous-classes de Jay peut être trouvée dans le post de Joseph Kingry ici: Synchroniser les positions multilignes de la boîte de texte en C # . L’approche de Joseph sous-classe également mais ne nécessite pas de gestionnaire d’événements _VScroll. J’ai utilisé cette approche pour faire une liaison à 3 voies entre 3 boîtes et ajouté WM_HSCROLL.