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

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

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

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


person lesderid    schedule 29.09.2010    source источник
comment
Невозможно ответить, если вы не сообщите нам, какой тип графического интерфейса вы используете.   -  person mikerobi    schedule 29.09.2010


Ответы (5)


Да, вам придется создать собственное текстовое поле, чтобы вы могли обнаружить его прокрутку. Хитрость заключается в том, чтобы передать сообщение прокрутки в другое текстовое поле, чтобы оно прокручивалось синхронно. Это действительно хорошо работает только тогда, когда другое текстовое поле примерно такого же размера и имеет такое же количество строк.

Добавьте новый класс в свой проект и вставьте код, показанный ниже. Скомпилировать. Поместите два новых элемента управления из верхней части панели инструментов на форму. Установите свойство 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);
}
person Hans Passant    schedule 29.09.2010
comment
@Hans Passant: я хотел добиться того же, но в случае двух представлений списка. Я пытался использовать этот код, но он не работает. мне нужно добавить что-то в этом? - person Iorn Man; 06.02.2013
comment
@Hans Passant: Человек из Gr8, на самом деле я установил свойство приятеля не в том месте. гр8 работа. - person Iorn Man; 06.02.2013
comment
Любые мысли о редактировании ответа, чтобы включить колесо мыши и прокрутку с помощью клавиш курсора (+ домашняя страница/страница вверх/вниз и т. д.)? - person Dan W; 27.02.2015
comment
Это уже работает, единственная ошибка, которую вы можете сделать, это не попробовать. - person Hans Passant; 27.02.2015
comment
Как насчет того, когда вы перетаскиваете слайд прокрутки и нажимаете левую кнопку мыши, вы перемещаете слайд вверх и вниз, тогда список друзей не реагирует на прокрутку? - person Tiger Galo; 26.01.2018

Вы можете изменить эту строку:

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

к этому:

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

и он также будет поддерживать прокрутку колесиком мыши.

person John Willemse    schedule 16.11.2011
comment
К сожалению, несмотря на то, что это работает, прокрутка не синхронизируется с колесом мыши, и основное текстовое поле прокручивается быстрее, чем приятель. - person SurfingSanta; 22.08.2016
comment
Как насчет того, когда вы перетаскиваете слайд прокрутки и нажимаете левую кнопку мыши, вы перемещаете слайд вверх и вниз, тогда список друзей не реагирует на прокрутку? - person Tiger Galo; 24.01.2018

Решение Ханса Пассана было потрясающим. Однако мне нужно было синхронизировать три текстовых поля, а не только два.

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

Класс Синкбокса:

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;
}
person Morvael    schedule 19.06.2015

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

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

person g_man_super_g    schedule 08.06.2015

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

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

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);
}
person Michael Ros    schedule 29.05.2017