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

发布于 2024-09-10 20:52:44 字数 5100 浏览 4 评论 0原文

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

其他信息 - 2010 年 7 月 26 日,

我在 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' 的定义,并且没有扩展方法 'GetFirstVisibleLineIndex' 接受类型的第一个参数可以找到“System.Windows.Forms.TextBox”(您是否缺少 using 指令或程序集引用?)

其他信息 - 7/27/10

我正在努力实施 Jay 的实施建议一个新控件,但我无法将事件处理程序绑定到控件中。这是我到目前为止所得到的:

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

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

I have a C# application wherein there are two multiline textboxes side-by-side, each in one side of a split-container. I would like to synchronize their vertical scroll, so that when the user scrolls up or down one of the textboxes, the other textbox scrolls respectively in the same direction. Is there a way to do this? Thanks.

ADDITIONAL INFORMATION - 7/26/10

I found some interesting APIs on the MSDN website:

TextBox.GetFirstVisibleLineIndex Method
TextBox.GetLastVisibleLineIndex Method
TextBox.ScrollToLine Method

The documentation there looks promising, but my compiler (Microsoft Visual C# 2008 Express Edition) complains when I try to use it, even after adding the PresenationFramework as a Reference and inserting using System.Windows.Controls; at the top of the file:

Error 1 'System.Windows.Forms.TextBox' does not contain a definition for 'GetFirstVisibleLineIndex' and no extension method 'GetFirstVisibleLineIndex' accepting a first argument of type 'System.Windows.Forms.TextBox' could be found (are you missing a using directive or an assembly reference?)

ADDITIONAL INFORMATION - 7/27/10

I'm working on implementing Jay's suggestion of implementing a new control, but I'm having trouble tying the eventhandler into the control. Here's is what I have so far:

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

I should think that something like...

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

...would be needed to hook the vertical scroll event into the control, but as you can probably see, this does not work. Any suggestions would be appreciated. Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

酒与心事 2024-09-17 20:52:44

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

对您的编辑的回应:

注意:我假设您在申请表中的复制和粘贴过程中犯了一个小错误,并且 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 将创建一个具有正确签名的方法。

I subclassed a RichTextBox and listened for the WM_VSCROLL message to do what you're trying to do. Perhaps you can do that instead of using a TextBox.

RESPONSE TO YOUR EDIT:

Note: I'm assuming you made a minor error in the copy and paste in your Application form and that textBoxSyncBusTraffic == textBoxSync1

The problem is in your declaration of your control's VerticalScroll event, in this line:

this.textBoxSyncBusTraffic.VerticalScroll += new System.EventHandler(this.textBoxSyncBusTraffic_VerticalScroll); 
  1. Your custom controls need to subscribe to your controls' TextBoxSynchronizedScroll.vScrollEventHandler events (not to System.EventHandler).
  2. The method referenced in your event handler doesn't exist (at least not in the code you posted).

So change this:

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

To this:

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

This uses the correct event handler and references the method you need and already have.

Also, make sure that the declaration for textBoxSync2's VerticalScroll event looks like this:

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

Incidentally, there are a couple techniques you can use to make it easier to declare events:

The first is to use the form designer. If you open the Events window in the Properties window of an instance of your extended control in the forms designer, you'll see an event called VerticalScroll. Double click this item to have Visual Studio declare the event and create a method to call when the event fires.

There's also a shortcut you can use when you set up your event in code. You'll find that after you type the following code:

youtextBoxSync1.VerticalScroll +=

You'll be prompted to press Tab to finish the declaration. If you do this Visual Studio will create a method with the correct signature.

顾冷 2024-09-17 20:52:44

根据现有代码,我想出了以下内容。似乎对我有用。

class TextBoxSynchronizedScroll : TextBox
{
    public const int WM_VSCROLL = 0x115;

    List<TextBoxSynchronizedScroll> peers = new List<TextBoxSynchronizedScroll>();

    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

Based of the existing code I came up with the following. Seems to work for me.

class TextBoxSynchronizedScroll : TextBox
{
    public const int WM_VSCROLL = 0x115;

    List<TextBoxSynchronizedScroll> peers = new List<TextBoxSynchronizedScroll>();

    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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文