C#:同步两个RichTextBox的滚动位置?

在我的应用程序的表单中,我有两个RichTextBox对象。 它们将始终具有相同数量的文本行。 我想“同步”这两者之间的垂直滚动,这样当用户在一个上改变垂直滚动位置时,另一个滚动相同的量。 我该怎么做呢?

我刚才为一个小项目做过这个,这是我发现的简单解决方案。

通过inheritanceRichTextBox创建一个新控件:

  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); } 

我认为如果所有“链接”控件没有相同数量的可显示行,则此代码存在问题。

谢谢杰伊的回答; 经过一番搜索,我也找到了这里描述的方法。 对于其他感兴趣的人,我将在下面概述。


首先,声明以下枚举:

 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 } 

接下来,添加对GetScrollPosSendMessage外部引用。

 [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 ); 

最后,为适当的RichTextBoxVScroll事件添加一个事件处理程序:

 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同步。

[Windows 7 64位安装上的Visual Studio C#2010 Express,v10.0.30319]

我已经使用了上面发布的Donut的解决方案,但在滚动到包含许多行的RichTextBox的末尾时发现了一个问题。

如果GetScrollPos()的结果>0x7FFF则当nPos移位时,顶部位置位。 使用生成的wParam变量创建IntPtr将失败并出现OverflowException 。 您可以使用以下内容轻松测试(第二行将失败):

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

使用UIntPtrSendMessage()版本似乎是一个解决方案,但我无法UIntPtr工作。 所以,我使用以下内容:

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

这应该是优秀的0xffff ,但之后会失败。 我还没有遇到来自GetScrollPos()>0xffff结果,并且假设User32.dll不太可能有64位版本的SendCommand() ,但是对此问题的任何解决方案都将非常感激。

Jay的子类方法的变体可以在Joseph Kingry的post中找到: 在C#中同步多行文本框位置 。 Joseph的方法也是子类,但不需要_VScroll事件处理程序。 我使用这种方法在3个盒子之间进行3向绑定并添加了WM_HSCROLL。