С#: Синхронизировать положение прокрутки двух RichTextBoxes?
В моей форме приложения у меня есть два объекта RichTextBox
. Они оба будут иметь одинаковое количество строк текста. Я хотел бы "синхронизировать" вертикальную прокрутку между этими двумя, так что, когда пользователь меняет положение вертикальной прокрутки на один, другой прокручивает ту же сумму. Как я могу это сделать?
Ответы
Ответ 1
Я сделал это для небольшого проекта некоторое время назад, и вот упрощенное решение, которое я нашел.
Создайте новый элемент управления путем подкласса 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);
}
Я думаю, что этот код имеет проблемы, если все "связанные" элементы управления не имеют одинакового количества отображаемых строк.
Ответ 2
Спасибо Джей за ваш ответ; после некоторого поиска я также нашел способ, описанный здесь. Я расскажу об этом ниже для всех, кого это интересует.
Сначала объявите следующие перечисления:
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
.
Ответ 3
[Visual Studio С# 2010 Express, v10.0.30319 на установке Windows 7 с 64-разрядной версией]
Я использовал решение Donut выше, но обнаружил проблему при прокрутке до конца RichTextBoxes, которые содержат много строк.
Если результат 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()
, но любые решения этой проблемы будут с благодарностью.
Ответ 4
Вариант подкласса Jay можно найти в сообщении Джозефа Кингри здесь: Синхронизация многострочных позиций текстового поля в С#. Джозеф также подклассы, но не требует обработчика события _VScroll. Я использовал этот подход, чтобы выполнить трехстороннее связывание между 3-мя ящиками и добавленным WM_HSCROLL.