【问题标题】:How can I sync the scrolling of two multiline textboxes?如何同步两个多行文本框的滚动?
【发布时间】:2011-04-18 21:37:47
【问题描述】:

如何在 C# (WinForms) 中同步两个多行文本框的滚动?

当您在 TextBox A 中向上/向下滚动一行时,TextBox B 也应该向上/向下滚动。 反之亦然。

如果没有自定义控件,这是否可以实现?

【问题讨论】:

  • 除非您告诉我们您使用的是什么类型的 GUI 框架,否则无法回答。

标签: c# winforms textbox scroll multiline


【解决方案1】:

是的,您必须创建一个自定义文本框,以便检测它的滚动。诀窍是将滚动消息传递给另一个文本框,使其同步滚动。这只有在其他文本框大小相同且行数相同时才有效。

向您的项目添加一个新类并粘贴如下所示的代码。编译。将工具箱顶部的两个新控件拖放到表单上。将 Buddy 属性设置为两者上的另一个控件。运行,在它们中输入一些文本,然后在拖动滚动条时观察它们同步滚动。

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;

class SyncTextBox : TextBox {
    public SyncTextBox() {
        this.Multiline = true;
        this.ScrollBars = ScrollBars.Vertical;
    }
    public Control Buddy { get; set; }

    private static bool scrolling;   // In case buddy tries to scroll us
    protected override void WndProc(ref Message m) {
        base.WndProc(ref m);
        // Trap WM_VSCROLL message and pass to buddy
        if (m.Msg == 0x115 && !scrolling && Buddy != null && Buddy.IsHandleCreated) {
            scrolling = true;
            SendMessage(Buddy.Handle, m.Msg, m.WParam, m.LParam);
            scrolling = false;
        }
    }
    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);
}

【讨论】:

  • @Hans Passant :我想实现类似但在两个列表视图的情况下。我尝试使用此代码,但它不起作用。我需要在其中添加一些东西吗?
  • @Hans Passant:Gr8 伙计,实际上我在错误的地方设置了好友财产。 gr8 工作。
  • 对编辑答案以包括鼠标滚轮和使用光标键滚动(+主页/向上/向下等)有任何想法吗?
  • 已经可以了,唯一的错误就是不尝试。
  • 当您拖动滚动幻灯片并按下鼠标左键时,您如何上下移动幻灯片,好友列表视图不会对滚动做出反应?
【解决方案2】:

你可以改变这一行:

if (m.Msg == 0x115) && !scrolling && Buddy != null && Buddy.IsHandleCreated)

到这里:

if ((m.Msg == 0x115 || m.Msg==0x20a) && !scrolling && Buddy != null && Buddy.IsHandleCreated)

它也将支持使用鼠标滚轮滚动。

【讨论】:

  • 不幸的是,虽然这似乎可行,但滚动与鼠标滚轮不同步,并且主文本框的滚动速度比伙伴快。
  • 当您拖动滚动幻灯片并按下鼠标左键时,您如何上下移动幻灯片,好友列表视图不会对滚动做出反应?
【解决方案3】:

Hans Passant 的解决方案很有魅力,但我需要一个带有水平和垂直滚动条的 RichTextBox。如果您扩展 RichTextBox 而不是 TextBox,则需要相应地更改 ScrollBars 属性(我使用的是 RichTextBoxScrollBars.Both)。

如果您还想同步水平滚动,请查找(m.Msg == 0x115) || (m.Msg == 0x114)

【讨论】:

    【解决方案4】:

    Hans Passant 的解决方案非常棒。但是我需要同步三个文本框而不仅仅是两个。

    所以我对其进行了一些修改 - 但所有的信任都应该归功于 Hans,如果没有他的工作,我什至不可能接近 - 我想我会把它发回这里以防其他人需要。

    SyncBox 类:

    using System;
    using System.Windows.Forms;
    using System.Runtime.InteropServices;
    
    class SyncTextBox : TextBox
    {
        public SyncTextBox()
        {
            this.Multiline = true;
            this.ScrollBars = ScrollBars.Vertical;
        }
    
        public Control[] Buddies { get; set; }
    
        private static bool scrolling;   // In case buddy tries to scroll us
        protected override void WndProc(ref Message m)
        {
            base.WndProc(ref m);
            // Trap WM_VSCROLL message and pass to buddy
            if (Buddies != null)
            {
                foreach (Control ctr in Buddies)
                {
                    if (ctr != this)
                    {
                        if ((m.Msg == 0x115 || m.Msg == 0x20a) && !scrolling && ctr.IsHandleCreated)
                        {
                            scrolling = true;
                            SendMessage(ctr.Handle, m.Msg, m.WParam, m.LParam);
                            scrolling = false;
                        }
                    }
                }
            }
        }
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);
    }
    

    然后在表单初始化器中:

    // add the required controls into scroll sync
    Control[] syncedCtrls = new Control[] { ctrl1, ctrl2, ..., ctrln };
    foreach (SyncTextBox ctr in syncedCtrls)
    {
        ctr.Buddies = syncedCtrls;
    }
    

    【讨论】:

      【解决方案5】:

      这是最终帮助我使用鼠标滚轮修复多个文本框同步问题的方法。

      我以非常有用的 Hans 示例为基础。

      int WM_MOUSEWHEEL   = 0x20a; // or 522
      int WM_VSCROLL      = 0x115; // or 277
      
      protected override void WndProc(ref Message m)
      {
              //Trap WM_VSCROLL and WM_MOUSEWHEEL message and pass to buddy
              if (Buddies != null)
              {
      
                  if (m.Msg == WM_MOUSEWHEEL)  //mouse wheel 
                  {
      
                      if ((int)m.WParam < 0)  //mouse wheel scrolls down
                          SendMessage(this.Handle, (int)0x0115, new IntPtr(1), new IntPtr(0)); //WParam: 1- scroll down, 0- scroll up
                      else if ((int)m.WParam > 0)
                          SendMessage(this.Handle, (int)0x0115, new IntPtr(0), new IntPtr(0));
      
      
      
                      return; //prevent base.WndProc() from messing synchronization up 
                  }
                  else if (m.Msg == WM_VSCROLL)
                  {
                      foreach (Control ctr in Buddies)
                      {
                          if (ctr != this && !scrolling && ctr != null && ctr.IsHandleCreated)
                          {
                              scrolling = true;
                              SendMessage(ctr.Handle, m.Msg, m.WParam, m.LParam);
                              scrolling = false;
                          }
      
                      }
      
                  }
              }
      
          //do the usual
          base.WndProc(ref m);
      }
      

      【讨论】:

        猜你喜欢
        • 2018-08-10
        • 1970-01-01
        • 2015-03-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-05-03
        • 2012-08-15
        • 1970-01-01
        相关资源
        最近更新 更多