Synchronisation des positions de zone de texte multiligne en C #

J’ai une application C # dans laquelle il y a deux zones de texte multilignes côte à côte, chacune dans un côté d’un conteneur divisé. J’aimerais synchroniser leur défilement vertical afin que, lorsque l’utilisateur fait défiler l’une des zones de texte vers le haut ou vers le bas, l’autre zone de texte défile dans la même direction. Y a-t-il un moyen de faire cela? Merci.

INFORMATIONS SUPPLÉMENTAIRES – 26/07/10

J’ai trouvé des API intéressantes sur le site Web MSDN:

TextBox.GetFirstVisibleLineIndex, méthode
TextBox.GetLastVisibleLineIndex, méthode
Méthode TextBox.ScrollToLine

La documentation semble prometteuse, mais mon compilateur (Microsoft Visual C # 2008 Express Edition) se plaint lorsque je tente de l’utiliser, même après avoir ajouté PresenationFramework tant que référence et inséré à l’ using System.Windows.Controls; en haut du fichier:

Erreur 1 ‘System.Windows.Forms.TextBox’ ne contient pas de définition pour ‘GetFirstVisibleLineIndex’ et aucune méthode d’extension ‘GetFirstVisibleLineIndex’ n’accepte un premier argument de type ‘System.Windows.Forms.TextBox’ (il vous manque un utilisant une directive ou une référence d’assemblage?)

INFORMATIONS COMPLÉMENTAIRES – 27/07/10

Je travaille sur la mise en œuvre de la suggestion de Jay de mettre en place un nouveau contrôle, mais j’ai du mal à lier le gestionnaire d’événements au contrôle. Voici ce que j’ai jusqu’à présent:

 public partial class MyFormApplication : Form { public MyFormApplication() // MyFormApplication constructor { this.InitializeComponent(); this.textBox1.Dispose(); // Replacing with textBoxSync1 this.textBox2.Dispose(); // Replacing with textBoxSync2 // Draw textBoxSync1 this.textBoxSync1.AcceptsReturn = true; this.textBoxSync1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.textBoxSync1.BackColor = System.Drawing.SystemColors.Control; this.textBoxSync1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; this.textBoxSync1.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.textBoxSync1.Location = new System.Drawing.Point(0, 19); this.textBoxSync1.Multiline = true; this.textBoxSync1.Name = "textBoxSync1"; this.textBoxSync1.ReadOnly = true; this.textBoxSync1.ScrollBars = System.Windows.Forms.ScrollBars.Both; this.textBoxSync1.Size = new System.Drawing.Size(338, 231); this.textBoxSync1.TabIndex = 0; this.textBoxSync1.TabStop = false; this.textBoxSync1.WordWrap = false; this.splitContainer1.Panel1.Controls.Remove(this.textBox1); this.splitContainer1.Panel1.Controls.Add(this.textBoxSync1); // Draw textBoxSync2 this.textBoxSync2.AcceptsReturn = true; this.textBoxSync2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.textBoxSync2.BackColor = System.Drawing.SystemColors.Control; this.textBoxSync2.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; this.textBoxSync2.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.textBoxSync2.Location = new System.Drawing.Point(0, 19); this.textBoxSync2.Multiline = true; this.textBoxSync2.Name = "textBoxSync2"; this.textBoxSync2.ReadOnly = true; this.textBoxSync2.ScrollBars = System.Windows.Forms.ScrollBars.Both; this.textBoxSync2.Size = new System.Drawing.Size(113, 231); this.textBoxSync2.TabIndex = 30; this.textBoxSync2.TabStop = false; this.textBoxSync2.WordWrap = false; this.splitContainer1.Panel2.Controls.Remove(this.textBox2); this.splitContainer1.Panel2.Controls.Add(this.textBoxSync2); /* Goes on to perform other initializations... */ } private void textBoxSync1_VerticalScroll(Message msg) { msg.HWnd = this.textBoxSync2.Handle; this.textBoxSync2.PubWndProc(ref msg); } private void textBoxSync2_VerticalScroll(Message msg) { msg.HWnd = this.textBoxSync1.Handle; this.textBoxSync1.PubWndProc(ref msg); } } public class TextBoxSynchronizedScroll : System.Windows.Forms.TextBox { public event vScrollEventHandler VerticalScroll; 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 (VerticalScroll != null) { VerticalScroll(msg); } } base.WndProc(ref msg); } public void PubWndProc(ref System.Windows.Forms.Message msg) { base.WndProc(ref msg); } } 

Je devrais penser que quelque chose comme …

 this.textBoxSync1.VerticalScroll += new System.EventHandler(this.textBoxSync1_VerticalScroll); 

… serait nécessaire pour lier l’événement de défilement vertical au contrôle, mais comme vous pouvez probablement le constater, cela ne fonctionne pas. Toute suggestion serait appréciée. Merci.

J’ai sous-classé un RichTextBox et écouté le message WM_VSCROLL pour faire ce que vous essayez de faire. Peut-être que vous pouvez le faire au lieu d’utiliser une zone de texte.

RÉPONSE À VOTRE ÉDIT:

Remarque: je suppose que vous avez commis une erreur mineure lors du copier-coller dans votre formulaire de demande et que textBoxSyncBusTraffic == textBoxSync1

Le problème réside dans votre déclaration de l’événement VerticalScroll de votre contrôle, dans cette ligne:

 this.textBoxSyncBusTraffic.VerticalScroll += new System.EventHandler(this.textBoxSyncBusTraffic_VerticalScroll); 
  1. Vos contrôles personnalisés doivent s’abonner aux événements TextBoxSynchronizedScroll.vScrollEventHandler de vos contrôles (et non à System.EventHandler).
  2. La méthode référencée dans votre gestionnaire d’événements n’existe pas (du moins pas dans le code que vous avez posté).

Alors changez ceci:

 this.textBoxSyncBusTraffic.VerticalScroll += new System.EventHandler(this.textBoxSyncBusTraffic_VerticalScroll); 

Pour ça:

 this.textBoxSync1.VerticalScroll += new TextBoxSynchronizedScroll.vScrollEventHandler(textBoxSync1_VerticalScroll); 

Ceci utilise le bon gestionnaire d’événements et fait référence à la méthode dont vous avez besoin et que vous avez déjà.

Assurez-vous également que la déclaration de l’événement VerticalScroll de textBoxSync2 ressemble à ceci:

 this.textBoxSync2.VerticalScroll += new TextBoxSynchronizedScroll.vScrollEventHandler(textBoxSync2_VerticalScroll); 

Incidemment, il existe plusieurs techniques que vous pouvez utiliser pour faciliter la déclaration d’événements:

La première consiste à utiliser le concepteur de formulaire. Si vous ouvrez la fenêtre Événements dans la fenêtre Propriétés d’une instance de votre contrôle étendu dans le concepteur de formulaires, vous verrez un événement appelé VerticalScroll. Double-cliquez sur cet élément pour que Visual Studio déclare l’événement et crée une méthode à appeler lors du déclenchement de l’événement.

Il existe également un raccourci que vous pouvez utiliser lorsque vous configurez votre événement dans le code. Vous constaterez qu’après avoir tapé le code suivant:

 youtextBoxSync1.VerticalScroll += 

Vous serez invité à appuyer sur Tabulation pour terminer la déclaration. Si vous faites cela, Visual Studio créera une méthode avec la signature correcte.

Basé sur le code existant, je suis venu avec ce qui suit. Semble travailler pour moi.

 class TextBoxSynchronizedScroll : TextBox { public const int WM_VSCROLL = 0x115; List peers = new List(); public void AddPeer(TextBoxSynchronizedScroll peer) { this.peers.Add(peer); } private void DirectWndProc(ref Message m) { base.WndProc(ref m); } protected override void WndProc(ref Message m) { if (m.Msg == WM_VSCROLL) { foreach (var peer in this.peers) { var peerMessage = Message.Create(peer.Handle, m.Msg, m.WParam, m.LParam); peer.DirectWndProc(ref peerMessage); } } base.WndProc(ref m); } } 

http://gist.github.com/593809