C #: Синхронизировать положение прокрутки двух RichTextBoxes? - PullRequest
16 голосов
/ 01 декабря 2009

В форме моего приложения у меня есть два RichTextBox объекта. У них обоих всегда будет одинаковое количество строк текста. Я хотел бы «синхронизировать» вертикальную прокрутку между этими двумя, чтобы, когда пользователь изменяет положение вертикальной прокрутки на одну, другая прокручивает ту же сумму. Как я могу сделать это?

Ответы [ 4 ]

20 голосов
/ 01 декабря 2009

Спасибо, Джей, за твой ответ; после еще нескольких поисков я также нашел метод, описанный здесь . Я обрисую это ниже для всех, кто заинтересован.


Сначала объявите следующие перечисления:

public enum ScrollBarType : uint {
   SbHorz = 0,
   SbVert = 1,
   SbCtl = 2,
   SbBoth = 3
 }

public enum Message : uint {
   WM_VSCROLL = 0x0115
}

public enum ScrollBarCommands : uint {
   SB_THUMBPOSITION = 4
}

Затем добавьте внешние ссылки на GetScrollPos и SendMessage.

[DllImport( "User32.dll" )]
public extern static int GetScrollPos( IntPtr hWnd, int nBar );

[DllImport( "User32.dll" )]
public extern static int SendMessage( IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam );

Наконец, добавьте обработчик события VScroll соответствующего RichTextBox:

private void myRichTextBox1_VScroll( object sender, EventArgs e )
{
   int nPos = GetScrollPos( richTextBox1.Handle, (int)ScrollBarType.SbVert );
   nPos <<= 16;
   uint wParam = (uint)ScrollBarCommands.SB_THUMBPOSITION | (uint)nPos;
   SendMessage( richTextBox2.Handle, (int)Message.WM_VSCROLL, new IntPtr( wParam ), new IntPtr( 0 ) );
}

В этом случае положение вертикальной прокрутки richTextBox2 будет синхронизировано с richTextBox1.

15 голосов
/ 01 декабря 2009

Я сделал это для небольшого проекта некоторое время назад, и вот простейшее решение, которое я нашел.

Создание нового элемента управления путем создания подкласса RichTextBox:

   public class SynchronizedScrollRichTextBox : System.Windows.Forms.RichTextBox
    {
        public event vScrollEventHandler vScroll;
        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 (vScroll != null) {
                    vScroll(msg);
                }
            }
            base.WndProc(ref msg);
        }

        public void PubWndProc(ref System.Windows.Forms.Message msg) {
            base.WndProc(ref msg);
        }
    }     

Добавьте новый элемент управления в форму и для каждого элемента управления явно уведомите другие экземпляры элемента управления об изменении его позиции vScroll. Что-то вроде этого:

private void scrollSyncTxtBox1_vScroll(Message msg) {
    msg.HWnd = scrollSyncTxtBox2.Handle;
    scrollSyncTxtBox2.PubWndProc(ref msg);
}

Я думаю, что этот код имеет проблемы, если все «связанные» элементы управления не имеют одинаковое количество отображаемых строк.

4 голосов
/ 06 декабря 2011

[Visual Studio C # 2010 Express, v10.0.30319 в 64-битной установке Windows 7]

Я использовал решение Donut, опубликованное выше, но обнаружил проблему при прокрутке до конца RichTextBox, который содержит много строк.

Если результат GetScrollPos() равен >0x7FFF, то при сдвиге nPos устанавливается верхний бит. Создание IntPtr с результирующей переменной wParam завершится неудачей с OverflowException. Вы можете легко проверить это с помощью следующего (вторая строка потерпит неудачу):

    IntPtr ip = new IntPtr(0x7FFF0000);
    IntPtr ip2 = new IntPtr(0x80000000);

Версия SendMessage(), которая использует UIntPtr, может показаться решением, но я не мог заставить это работать. Итак, я использую следующее:

    [DllImport("User32.dll")]
    public extern static int SendMessage(IntPtr hWnd, uint msg, UInt32 wParam, UInt32 lParam);

Это должно быть хорошо до 0xffff, но после этого потерпит неудачу. Я еще не получил >0xffff результат от GetScrollPos() и предполагаю, что User32.dll вряд ли будет иметь 64-битную версию SendCommand(), но любые решения этой проблемы будут с благодарностью.

1 голос
/ 16 марта 2011

Вариант подхода подкласса Джея можно найти в посте Джозефа Кингри здесь: Синхронизация позиций многострочного текстового поля в C # . Подход Джозефа также подклассов, но не требует обработчик события _VScroll. Я использовал этот подход для трехстороннего связывания между 3 блоками и добавил WM_HSCROLL.

...