Как синхронизировать прокрутку двух многострочных текстовых полей?
Как синхронизировать прокрутку двух многострочных текстовых полей в С# (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);
}