【发布时间】:2011-04-18 21:37:47
【问题描述】:
如何在 C# (WinForms) 中同步两个多行文本框的滚动?
当您在 TextBox A 中向上/向下滚动一行时,TextBox B 也应该向上/向下滚动。 反之亦然。
如果没有自定义控件,这是否可以实现?
【问题讨论】:
-
除非您告诉我们您使用的是什么类型的 GUI 框架,否则无法回答。
标签: c# winforms textbox scroll multiline
如何在 C# (WinForms) 中同步两个多行文本框的滚动?
当您在 TextBox A 中向上/向下滚动一行时,TextBox B 也应该向上/向下滚动。 反之亦然。
如果没有自定义控件,这是否可以实现?
【问题讨论】:
标签: c# winforms textbox scroll multiline
是的,您必须创建一个自定义文本框,以便检测它的滚动。诀窍是将滚动消息传递给另一个文本框,使其同步滚动。这只有在其他文本框大小相同且行数相同时才有效。
向您的项目添加一个新类并粘贴如下所示的代码。编译。将工具箱顶部的两个新控件拖放到表单上。将 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);
}
【讨论】:
你可以改变这一行:
if (m.Msg == 0x115) && !scrolling && Buddy != null && Buddy.IsHandleCreated)
到这里:
if ((m.Msg == 0x115 || m.Msg==0x20a) && !scrolling && Buddy != null && Buddy.IsHandleCreated)
它也将支持使用鼠标滚轮滚动。
【讨论】:
Hans Passant 的解决方案很有魅力,但我需要一个带有水平和垂直滚动条的 RichTextBox。如果您扩展 RichTextBox 而不是 TextBox,则需要相应地更改 ScrollBars 属性(我使用的是 RichTextBoxScrollBars.Both)。
如果您还想同步水平滚动,请查找(m.Msg == 0x115) || (m.Msg == 0x114)。
【讨论】:
Hans Passant 的解决方案非常棒。但是我需要同步三个文本框而不仅仅是两个。
所以我对其进行了一些修改 - 但所有的信任都应该归功于 Hans,如果没有他的工作,我什至不可能接近 - 我想我会把它发回这里以防其他人需要。
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;
}
【讨论】:
这是最终帮助我使用鼠标滚轮修复多个文本框同步问题的方法。
我以非常有用的 Hans 示例为基础。
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);
}
【讨论】: