【问题标题】:Synchronize Scroll Position of two RichTextBoxes?同步两个 RichTextBox 的滚动位置?
【发布时间】:2010-12-22 02:09:15
【问题描述】:

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

【问题讨论】:

    标签: c# .net winforms scroll richtextbox


    【解决方案1】:

    @Sudhakar MuthuKrishnan 的回答需要一些修复,但可以。谢谢!

    首先 GetScrollPos 上升事件,然后为其他人设置滚动位置。

    private void RichTextBox1_VScroll(object sender, EventArgs e)
    {
        Point pt = new Point();
    
        SendMessage(RichTextBox1.Handle, EM_GETSCROLLPOS, 0, ref pt);
    
        SendMessage(RichTextBox2.Handle, EM_SETSCROLLPOS, 0, ref pt);
    }
    
    
    private void RichTextBox2_VScroll(object sender, EventArgs e)
    {
        Point pt = new Point();
    
        SendMessage(RichTextBox2.Handle, EM_GETSCROLLPOS, 0, ref pt);
    
        SendMessage(RichTextBox1.Handle, EM_SETSCROLLPOS, 0, ref pt);
    }
    

    【讨论】:

      【解决方案2】:

      可以在 Joseph Kingry 的回答中找到 Jay 的子类方法的变体:Synchronizing Multiline Textbox Positions in C#

      Joseph 的方法也是子类,但不需要 _VScroll 事件处理程序。我使用这种方法在 3 个盒子之间进行 3 向绑定,并添加了 WM_HSCROLL。

      【讨论】:

        【解决方案3】:
        const int WM_USER = 0x400;
        
        const int EM_GETSCROLLPOS = WM_USER + 221;
        
        const int EM_SETSCROLLPOS = WM_USER + 222;
        
        [System.Runtime.InteropServices.DllImport("user32.dll")]
        static extern int SendMessage(IntPtr hWnd, int msg, int wParam, ref Point lParam);
        
        private void RichTextBox1_VScroll(object sender, EventArgs e)
        {
            Point pt;
        
            SendMessage(RichTextBox1.Handle, EM_GETSCROLLPOS, 0, ref pt);
        
            SendMessage(RichTextBox2.Handle, EM_SETSCROLLPOS, 0, ref pt);
        }
        
        
        private void RichTextBox2_VScroll(object sender, EventArgs e)
        {
            Point pt;
        
            SendMessage(RichTextBox1.Handle, EM_GETSCROLLPOS, 0, ref pt);
        
            SendMessage(RichTextBox2.Handle, EM_SETSCROLLPOS, 0, ref pt);
        }
        

        【讨论】:

          【解决方案4】:

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

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

          如果GetScrollPos() 的结果是>0x7FFF,那么当nPos 移位时,最高位被设置。使用生成的wParam 变量创建IntPtr 将失败并返回OverflowException。您可以使用以下内容轻松测试(第二行将失败):

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

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

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

          这在0xffff 之前应该是好的,但在那之后会失败。我还没有体验到来自GetScrollPos()>0xffff 结果,并假设User32.dll 不太可能有SendCommand() 的64 位版本,但任何解决该问题的方法将不胜感激。

          【讨论】:

            【解决方案5】:

            感谢周杰伦的回答;经过一番搜索,我还找到了here 描述的方法。我将在下面为其他感兴趣的人概述它。


            首先,声明以下枚举:

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

            【讨论】:

            • 很棒的总结。节省了我很多时间。谢谢!
            【解决方案6】:

            前段时间我为一个小项目做了这个,这是我找到的最简单的解决方案。

            通过继承 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);
            }
            

            如果所有“链接”控件的可显示行数不同,我认为这段代码有问题。

            【讨论】:

            • 此方法可以通过移动滚动条进行滚动。但是滚动条在 (1) 使用鼠标滚轮滚动 (2) 通过 page downpage up 键滚动 - 按箭头键滚动时不同步
            • @Jay riggs 'System.Windows.Forms.RichTextBox' 不包含 'PubWndProc' 的定义,并且没有扩展方法 'PubWndProc' 接受类型为 'System.Windows.Forms.RichTextBox' 的第一个参数' 可以找到(您是否缺少 using 指令或程序集引用?)
            猜你喜欢
            • 1970-01-01
            • 2012-03-03
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多