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

Jim*_*ell 6 c# scroll synchronization textbox

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

其他信息 - 7/26/10

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

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

那里的文档看起来很有希望,但是当我尝试使用它时,我的编译器(Microsoft Visual C#2008 Express Edition)就会抱怨,即使在添加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);
  }
}
Run Code Online (Sandbox Code Playgroud)

我应该认为......

this.textBoxSync1.VerticalScroll += new System.EventHandler(this.textBoxSync1_VerticalScroll);
Run Code Online (Sandbox Code Playgroud)

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

Jay*_*ggs 4

对 RichTextBox 进行了子类化并侦听 WM_VSCROLL 消息来执行您想要执行的操作。也许您可以这样做,而不是使用文本框。

回复您的编辑:

注意:我假设您在复制和粘贴申请表时犯了一个小错误,并且 textBoxSyncBusTraffic == textBoxSync1

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

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

所以改变这个:

this.textBoxSyncBusTraffic.VerticalScroll += new System.EventHandler(this.textBoxSyncBusTraffic_VerticalScroll); 
Run Code Online (Sandbox Code Playgroud)

对此:

this.textBoxSync1.VerticalScroll += new TextBoxSynchronizedScroll.vScrollEventHandler(textBoxSync1_VerticalScroll);
Run Code Online (Sandbox Code Playgroud)

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

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

this.textBoxSync2.VerticalScroll += new TextBoxSynchronizedScroll.vScrollEventHandler(textBoxSync2_VerticalScroll);
Run Code Online (Sandbox Code Playgroud)

顺便说一句,您可以使用一些技术来更轻松地声明事件:

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

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

youtextBoxSync1.VerticalScroll +=
Run Code Online (Sandbox Code Playgroud)

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