在C#中同步多行文本框位置

我有一个C#应用程序,其中有两个并排的多行文本框,每个文本框位于拆分容器的一侧。 我想同步它们的垂直滚动,这样当用户向上或向下滚动其中一个文本框时,另一个文本框分别向同一方向滚动。 有没有办法做到这一点? 谢谢。

其他资料 – 7/26/10

我在MSDN网站上找到了一些有趣的API:

TextBox.GetFirstVisibleLineIndex方法
TextBox.GetLastVisibleLineIndex方法
TextBox.ScrollToLine方法

那里的文档看起来很有希望,但是当我尝试使用它时,我的编译器(Microsoft Visual C#2008 Express Edition)抱怨,即使在将PresenationFramework添加为Reference并using System.Windows.Controls;插入之后也是PresenationFramework using System.Windows.Controls; 在文件的顶部:

错误1’System.Windows.Forms.TextBox’不包含’GetFirstVisibleLineIndex’的定义,并且没有可以找到接受类型’System.Windows.Forms.TextBox’的第一个参数的扩展方法’GetFirstVisibleLineIndex’(你错过了吗?使用指令或程序集引用?)

其他资料 – 7/27/10

我正在努力实现Jay的实现新控件的建议,但是我无法将eventhandler绑定到控件中。 这是我到目前为止所拥有的:

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

我应该认为……

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

…需要将垂直滚动事件挂钩到控件中,但正如您可能看到的那样,这不起作用。 任何建议,将不胜感激。 谢谢。

我将RichTextBox子类化并监听WM_VSCROLL消息以执行您要执行的操作。 也许你可以这样做,而不是使用TextBox。

回复您的编辑:

注意:我假设您在复制并粘贴到应用程序表单中时出现了一个小错误,而且textBoxSyncBusTraffic == textBoxSync1

问题出在你的控件的VerticalScroll事件声明中,在这一行:

 this.textBoxSyncBusTraffic.VerticalScroll += new System.EventHandler(this.textBoxSyncBusTraffic_VerticalScroll); 
  1. 您的自定义控件需要订阅控件的TextBoxSynchronizedScroll.vScrollEventHandler事件(而不是System.EventHandler)。
  2. 事件处理程序中引用的方法不存在(至少不在您发布的代码中)。

所以改变这个:

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

对此:

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

这使用正确的事件处理程序并引用您需要和已有的方法。

另外,请确保textBoxSync2的VerticalScroll事件的声明如下所示:

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

顺便提一下,您可以使用几种技术来更轻松地声明事件:

首先是使用表单设计器。 如果在窗体设计器中的扩展控件实例的“属性”窗口中打开“事件”窗口,则会看到名为VerticalScroll的事件。 双击此项以使Visual Studio声明事件并创建一个在事件触发时调用的方法。

在代码中设置事件时,还可以使用快捷方式。 键入以下代码后,您会发现:

 youtextBoxSync1.VerticalScroll += 

系统将提示您按Tab键完成声明。 如果这样做,Visual Studio将创建一个具有正确签名的方法。

根据现有代码,我提出了以下内容。 似乎适合我。

 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