Как синхронизировать прокрутку двух многострочных текстовых полей?

Как синхронизировать прокрутку двух многострочных текстовых полей в С# (WinForms)?

Когда вы прокручиваете вверх/вниз строку в TextBox A, TextBox B также должен прокручивать вверх/вниз. То же самое и наоборот.

Достижимо ли это без пользовательских элементов управления?

Ответы

Ответ 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);
}

Ответ 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 было потрясающим. Однако мне нужно было синхронизировать три текстовых поля не только из двух.

Итак, я немного изменил его, но все доверие должно идти к Гансу, и я не мог бы даже приблизиться к нему без его работы. Я думал, что отправлю его сюда, если другим нужны то же самое.

Класс 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;
}

Ответ 4

Решение Hans Passant работало как шарм, но мне нужен RichTextBox с горизонтальными и вертикальными полосами прокрутки. Если вы расширите RichTextBox вместо TextBox, вам необходимо соответствующим образом изменить свойство ScrollBars (я использовал RichTextBoxScrollBars.Both).

Если вы хотите также синхронизировать горизонтальную прокрутку, найдите (m.Msg == 0x115) || (m.Msg == 0x114).

Ответ 5

Вот что помогло мне исправить синхронизацию нескольких текстовых полей с помощью колеса мыши.

Я основал его на очень полезном примере Ганса.

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