如何同步两个多行文本框的滚动?

时间:2010-09-29 15:36:58

标签: c# winforms textbox scroll multiline

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

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

这是否可以在没有自定义控件的情况下实现?

5 个答案:

答案 0 :(得分:35)

是的,您必须创建一个自定义文本框,以便检测它是否滚动。诀窍是将滚动消息传递给另一个文本框,以便它同步滚动。这真的只适用于其他文本框大小相同且行数相同的情况。

在项目中添加一个新类并粘贴下面显示的代码。编译。将两个新控件从工具箱顶部拖放到表单上。将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);
}

答案 1 :(得分:8)

您可以更改此行:

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

到此:

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

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

答案 2 :(得分:3)

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

所以我稍微修改了一下 - 但是所有的信任都应该归到汉斯那里,如果没有他的工作,我甚至不会接近 - 我想我会把它发回去,以防其他人需要同样的东西。

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

然后在形式initilizer中:

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

答案 3 :(得分:2)

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

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

答案 4 :(得分:0)

最后帮助我使用鼠标滚轮修复了多个文本框的同步。

我基于非常有用的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);
}