Click here to Skip to main content
15,890,670 members
Articles / Programming Languages / Visual Basic
Article

Scrolling Around with the RichTextBox Control

Rate me:
Please Sign up or sign in to vote.
4.47/5 (13 votes)
29 Jul 20043 min read 180.4K   1.6K   40   28
Synchronized Scrolling of Multiple RichTextBox Controls

Image 1

Scrolling Around with the RichTextBox Control

Some of you may be saying about now, what the...!???!. Well, please read on. Because I actually had a need to vertically scroll multiple RichTextBox controls at the same time, with only one of the RichTextBoxes scrollbars controlling all three of them. Well that should be easy Right!, Yes and No, at least from what I have found so far.

I would like to say at this point, I welcome all the CP user's Input on this matter as I can get. As I searched around the internet, I found very little information on this matter.

Background

In the RichTextBox (and other controls), the scroll message VSCROLL/HSCROLL and THUMBPOSITION of the scroll bar are not inter-connected as one would expect. On a vertical line change up or down, or a horizontal character scroll right or left, the VSCROLL/HSCROLL messages fire an event and the scrollbar moves, but the new position of the thumb never gets sent. Instead, in the case of the RichTextBox, it fires the event RichTextBox1_VScroll (or _HScroll), but still with no thumb position information. This means in my case, "The Thumb has no Idea what the rest of the hand is doing."

This so far, is what I have come up with to deal with scrolling them. I haven't tried, but I think this will also work with other text controls as I did see some horizontal uses for this, including the following article here on CP.

MFC / C++ List Controls General - Synchronization of scrolling between two list controls By Alexander Khudyakov -

Using the code

It requires the use of two windows API functions, GetScrollPos and PostMessageA, and the infamous NativeWindow Class.

I chose Not to use the NativeWindow class at the last minute to send the GetScrollPos and PostMessageA messages because of a three line, cryptic explanation in the SDK Documentation that said: "Applications should not send these messages directly. Instead, they should use the GetScrollPos function. A window receives this message through its WindowProc function. Applications which implement a custom scroll bar control must respond to these messages for the GetScrollPos function to function properly." How this applies to the NativeWindow class I do not know yet, but I am seeking an answer if anyone knows off hand. My Original Intention was to Use the NativeWindow Class only.

I handled the GetScrollPos and PostMessageA using the RichTextBox VScroll/HScroll events.

VB.NET
Private Sub RichTextBox1_VScroll( _
ByVal sender As Object, ByVal e As System.EventArgs) _
  Handles RichTextBox1.VScroll
    Dim RTB1Position As Integer
    RTB1Position = GetScrollPos(RichTextBox1.Handle, SBS_VERT)
    PostMessageA(RichTextBox2.Handle, WM_VSCROLL, SB_THUMBPOSITION +_
       &H10000 * RTB1Position, 0)
    PostMessageA(RichTextBox3.Handle, WM_VSCROLL, SB_THUMBPOSITION +_
       &H10000 * RTB1Position, 0)
End Sub

And the WM_VSCROLL/WM_HSCROLL message's are handled by the NativeWindow Class.

VB.NET
Public Sub sClass_WindowProcedure( _
ByRef uMsg As Message) Handles sClass1.WindowProcedure, _
  sClass2.WindowProcedure, sClass3.WindowProcedure
    Select Case uMsg.Msg
        Case WM_VSCROLL ' WM_VSCROLL Message's for RTB's
            If uMsg.HWnd.Equals(RichTextBox1.Handle) Then
                'Debug.WriteLine(GetLowWord(uMsg.WParam.ToInt32))
                RemoveHandler sClass2.WindowProcedure, _
                 AddressOf sClass_WindowProcedure
                Dim msg1 As Message
                Dim msg2 As Message
                msg1 = uMsg.Create(RichTextBox2.Handle, _
                 uMsg.Msg, uMsg.WParam, uMsg.LParam)
                msg2 = uMsg.Create(RichTextBox3.Handle, _
                 uMsg.Msg, uMsg.WParam, uMsg.LParam)
                sClass2.SendWndProc(msg1)
                sClass2.SendWndProc(msg2)
                AddHandler sClass2.WindowProcedure, _
                 AddressOf sClass_WindowProcedure
             End If
'
' on to the next RTB.... ect.ect.

Points of Interest

There are a few small glitches to be aware of if you apply this to RichTextBoxes where the vertical line counts or the horizontal character counts are different. The scrollbars will get out of sync and won't resync until the Thumb or line Up event is fired again, sometimes moving it back to the last position in the richtextbox you selected. In the case of the Horizontal scroll it will make the shorter ones visibly "shake". But, this is not a problem in my application of this as all the Vertical line counts and the horizontal character counts are the same.

Also, Don't turn off the scroll bars in the property sheet, hide them under a panel control or something similar. The events won't fire on a disabled scrollbar and a handy "Object Not Set" Message will appear!.

Now, What I was Doing:

Image 2

Sorry, You won't find the source code for this HexDumper/Editor in my submission. But, I will try to get it up here to CP when I get more of it finished, or in the mean time you could just help me with this one or create your own. It is based on the source code I submitted.

I submitted the one at the top of the page, because it shows both scroll directions and how they interact together.

The Full Code Listing

VB.NET
Option Explicit On 

Imports System
Imports System.IO
Imports System.Data
Imports System.Text
Imports System.Drawing
Imports System.Collections
Imports System.Windows.Forms
Imports System.Windows.Forms.Message
Imports System.Runtime.InteropServices.Marshal

Public Class Form1
    Inherits System.Windows.Forms.Form

    '"Windows Form Designer generated code removed here"

    '===================================================================
    ' for NativeWindow and PostMessageA
    '===================================================================
    Private Const WM_HSCROLL = &H114
    Private Const WM_VSCROLL = &H115
    Private Const WM_MOUSEWHEEL = &H20A
    Private Const WM_COMMAND = &H111
    Private Const WM_USER = &H400
    '===================================================================
    ' for GetScroll and PostMessageA
    '===================================================================
    Private Const SBS_HORZ = 0
    Private Const SBS_VERT = 1
    Private Const SB_THUMBPOSITION = 4
    '===================================================================
    ' for SubClassing
    '===================================================================
    Private WithEvents sClass1 As Subclass
    Private WithEvents sClass2 As Subclass
    Private WithEvents sClass3 As Subclass

    Private Sub Form1_Load(ByVal sender As System.Object, _
      ByVal e As System.EventArgs) Handles MyBase.Load
        ' clear the rtb text
        RichTextBox1.Text = ""
        RichTextBox2.Text = ""
        RichTextBox3.Text = ""
        ' setup the sSubclass
        sClass1 = New Subclass(RichTextBox1.Handle)
        sClass2 = New Subclass(RichTextBox2.Handle)
        sClass3 = New Subclass(RichTextBox3.Handle)
        Dim i As Integer
        ' put some formated text in the RichTextBox's
        While i < 100
            RichTextBox1.AppendText(" this is a string " & i & vbCrLf)
            RichTextBox2.AppendText(" this is a string " & i & vbCrLf)
            RichTextBox3.AppendText(" this is a string " & i & vbCrLf)
            If i Mod 4 = 0 Then
                RichTextBox1.AppendText( _
                 " this is a longer string to force HScroll " & i & vbCrLf)
                RichTextBox2.AppendText( _
                 " this is a longer string to force HScroll " & i & vbCrLf)
                RichTextBox3.AppendText( _
                 " this is a longer string to force HScroll " & i & vbCrLf)
            End If
            i += 1
        End While
    End Sub
    Public Sub sClass_WindowProcedure( _ 
    ByRef uMsg As Message) Handles sClass1.WindowProcedure, _
     sClass2.WindowProcedure, sClass3.WindowProcedure
        Select Case uMsg.Msg
            Case WM_VSCROLL ' WM_VSCROLL Message's for RTB's
                If uMsg.HWnd.Equals(RichTextBox1.Handle) Then
                    'Debug.WriteLine(GetLowWord(uMsg.WParam.ToInt32))
                    RemoveHandler sClass2.WindowProcedure, _
                     AddressOf sClass_WindowProcedure
                    Dim msg1 As Message
                    Dim msg2 As Message
                    msg1 = uMsg.Create(RichTextBox2.Handle, _
                     uMsg.Msg, uMsg.WParam, uMsg.LParam)
                    msg2 = uMsg.Create(RichTextBox3.Handle, _
                     uMsg.Msg, uMsg.WParam, uMsg.LParam)
                    sClass2.SendWndProc(msg1)
                    sClass2.SendWndProc(msg2)
                    AddHandler sClass2.WindowProcedure, _
                     AddressOf sClass_WindowProcedure
                End If
                If uMsg.HWnd.Equals(RichTextBox2.Handle) Then
                    RemoveHandler sClass2.WindowProcedure, _
                     AddressOf sClass_WindowProcedure
                    Dim msg1 As Message
                    Dim msg2 As Message
                    msg1 = uMsg.Create(RichTextBox1.Handle, _
                      uMsg.Msg, uMsg.WParam, uMsg.LParam)
                    msg2 = uMsg.Create(RichTextBox3.Handle, _
                     uMsg.Msg, uMsg.WParam, uMsg.LParam)
                    sClass2.SendWndProc(msg1)
                    sClass2.SendWndProc(msg2)
                    AddHandler sClass2.WindowProcedure, _
                     AddressOf sClass_WindowProcedure
                End If
                If uMsg.HWnd.Equals(RichTextBox3.Handle) Then
                    RemoveHandler sClass2.WindowProcedure, _
                     AddressOf sClass_WindowProcedure
                    Dim msg1 As Message
                    Dim msg2 As Message
                    msg1 = uMsg.Create(RichTextBox1.Handle, _
                     uMsg.Msg, uMsg.WParam, uMsg.LParam)
                    msg2 = uMsg.Create(RichTextBox2.Handle, _
                     uMsg.Msg, uMsg.WParam, uMsg.LParam)
                    sClass2.SendWndProc(msg1)
                    sClass2.SendWndProc(msg2)
                    AddHandler sClass2.WindowProcedure, _
                     AddressOf sClass_WindowProcedure
                End If
            Case WM_HSCROLL ' WM_HSCROLL Message's for RTB's
                If uMsg.HWnd.Equals(RichTextBox1.Handle) Then
                    'Debug.WriteLine(GetLowWord(uMsg.WParam.ToInt32))
                    RemoveHandler sClass2.WindowProcedure, _
                     AddressOf sClass_WindowProcedure
                    Dim msg1 As Message
                    Dim msg2 As Message
                    msg1 = uMsg.Create(RichTextBox2.Handle, _
                     uMsg.Msg, uMsg.WParam, uMsg.LParam)
                    msg2 = uMsg.Create(RichTextBox3.Handle, _
                     uMsg.Msg, uMsg.WParam, uMsg.LParam)
                    sClass2.SendWndProc(msg1)
                    sClass2.SendWndProc(msg2)
                    AddHandler sClass2.WindowProcedure, _
                     AddressOf sClass_WindowProcedure
                End If
                If uMsg.HWnd.Equals(RichTextBox2.Handle) Then
                    RemoveHandler sClass2.WindowProcedure, _
                     AddressOf sClass_WindowProcedure
                    Dim msg1 As Message
                    Dim msg2 As Message
                    msg1 = uMsg.Create(RichTextBox1.Handle, _ 
                     uMsg.Msg, uMsg.WParam, uMsg.LParam)
                    msg2 = uMsg.Create(RichTextBox3.Handle, _
                     uMsg.Msg, uMsg.WParam, uMsg.LParam)
                    sClass2.SendWndProc(msg1)
                    sClass2.SendWndProc(msg2)
                    AddHandler sClass2.WindowProcedure, _
                     AddressOf sClass_WindowProcedure
                End If
                If uMsg.HWnd.Equals(RichTextBox3.Handle) Then
                    RemoveHandler sClass2.WindowProcedure, _
                     AddressOf sClass_WindowProcedure
                    Dim msg1 As Message
                    Dim msg2 As Message
                    msg1 = uMsg.Create(RichTextBox1.Handle, _
                     uMsg.Msg, uMsg.WParam, uMsg.LParam)
                    msg2 = uMsg.Create(RichTextBox2.Handle, _
                     uMsg.Msg, uMsg.WParam, uMsg.LParam)
                    sClass2.SendWndProc(msg1)
                    sClass2.SendWndProc(msg2)
                    AddHandler sClass2.WindowProcedure, _
                     AddressOf sClass_WindowProcedure
                End If
        End Select
    End Sub

    Private Sub RichTextBox1_VScroll(ByVal sender As Object, _
    ByVal e As System.EventArgs) Handles RichTextBox1.VScroll
        Dim RTB1Position As Integer
        RTB1Position = GetScrollPos(RichTextBox1.Handle, SBS_VERT)
        PostMessageA(RichTextBox2.Handle, WM_VSCROLL, _
        SB_THUMBPOSITION + &H10000 * RTB1Position, 0)
        PostMessageA(RichTextBox3.Handle, WM_VSCROLL, _
        SB_THUMBPOSITION + &H10000 * RTB1Position, 0)
    End Sub
    Private Sub RichTextBox2_VScroll(ByVal sender As Object,_
     ByVal e As System.EventArgs) Handles RichTextBox2.VScroll
        Dim RTB2Position As Integer
        RTB2Position = GetScrollPos(RichTextBox2.Handle, SBS_VERT)
        PostMessageA(RichTextBox1.Handle, WM_VSCROLL,_
         SB_THUMBPOSITION + &H10000 * RTB2Position, 0)
        PostMessageA(RichTextBox3.Handle, WM_VSCROLL, _
        SB_THUMBPOSITION + &H10000 * RTB2Position, 0)
    End Sub
    Private Sub RichTextBox3_VScroll(ByVal sender As Object, _
    ByVal e As System.EventArgs) Handles RichTextBox3.VScroll
        Dim RTB3Position As Integer
        RTB3Position = GetScrollPos(RichTextBox3.Handle, SBS_VERT)
        PostMessageA(RichTextBox1.Handle, WM_VSCROLL, _
        SB_THUMBPOSITION + &H10000 * RTB3Position, 0)
        PostMessageA(RichTextBox2.Handle, WM_VSCROLL, _
        SB_THUMBPOSITION + &H10000 * RTB3Position, 0)
    End Sub
    Private Sub RichTextBox1_HScroll(ByVal sender As Object,_
     ByVal e As System.EventArgs) Handles RichTextBox1.HScroll
        Dim RTB1Position As Integer
        RTB1Position = GetScrollPos(RichTextBox1.Handle, SBS_HORZ)
        PostMessageA(RichTextBox2.Handle, WM_HSCROLL,_
         SB_THUMBPOSITION + &H10000 * RTB1Position, 0)
        PostMessageA(RichTextBox3.Handle, WM_HSCROLL, _
        SB_THUMBPOSITION + &H10000 * RTB1Position, 0)
    End Sub
    Private Sub RichTextBox2_HScroll(ByVal sender As Object, _
    ByVal e As System.EventArgs) Handles RichTextBox2.HScroll
        Dim RTB2Position As Integer
        RTB2Position = GetScrollPos(RichTextBox2.Handle, SBS_HORZ)
        PostMessageA(RichTextBox1.Handle, WM_HSCROLL,_
         SB_THUMBPOSITION + &H10000 * RTB2Position, 0)
        PostMessageA(RichTextBox3.Handle, WM_HSCROLL,_
         SB_THUMBPOSITION + &H10000 * RTB2Position, 0)
    End Sub

    Private Sub RichTextBox3_HScroll(ByVal sender As Object,_
     ByVal e As System.EventArgs) Handles RichTextBox3.HScroll
        Dim RTB3Position As Integer
        RTB3Position = GetScrollPos(RichTextBox3.Handle, SBS_HORZ)
        PostMessageA(RichTextBox1.Handle, WM_HSCROLL, _
        SB_THUMBPOSITION + &H10000 * RTB3Position, 0)
        PostMessageA(RichTextBox2.Handle, WM_HSCROLL, _
        SB_THUMBPOSITION + &H10000 * RTB3Position, 0)
    End Sub
    '===================================================================
    ' API Function: GetScrollPos
    '===================================================================
    Private Declare Function GetScrollPos Lib "user32.dll" ( _
        ByVal hWnd As IntPtr, _
        ByVal nBar As Integer) As Integer
    '===================================================================
    ' API Function: PostMessageA
    '===================================================================
    Private Declare Function PostMessageA Lib "user32.dll" ( _
        ByVal hwnd As IntPtr, _
        ByVal wMsg As Integer, _
        ByVal wParam As Integer, _
        ByVal lParam As Integer) As Boolean
    '===================================================================
    ' Temporary Functions for the Debugger
    '===================================================================
    Public Function GetLowWord(ByRef pintValue As Int32) As Int32
        Return pintValue And &HFFFF
    End Function
    Public Function GetLowWord(ByRef pudtValue As IntPtr) As Int32
        Return GetLowWord(pudtValue.ToInt32)
    End Function
    Public Function GetHighWord(ByRef pintValue As Int32) As Int32
        If (pintValue And &H80000000) = &H80000000 Then
            Return ((pintValue And &H7FFF0000) \ &H10000) Or &H8000&
        Else
            Return (pintValue And &HFFFF0000) \ &H10000
        End If
    End Function
    '===================================================================
    ' End Temporary Functions for the Debugger
    '===================================================================
End Class

Public Class Subclass
    '===================================================================
    ' NativeWindow Subclassing
    '===================================================================
    Inherits System.Windows.Forms.NativeWindow
    Public Event WindowProcedure(ByRef uMsg As Message)

    Public Sub New(ByVal pWindowHandle As IntPtr)
        MyBase.AssignHandle(pWindowHandle)
    End Sub

    Protected Overrides Sub WndProc( _
     ByRef uMsg As System.Windows.Forms.Message)
        MyBase.WndProc(uMsg)
        RaiseEvent WindowProcedure(uMsg)
    End Sub

    Public Sub SendWndProc(ByRef uMsg As System.Windows.Forms.Message)
        MyBase.WndProc(uMsg)
    End Sub

End Class

Please, feel free to let me know if I'm re-inventing the wheel here, There might be a better way, And I could use the feedback.

History

  • Submitted: Monday, July 26, 2004

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionWhat to if the font size is diffrent Pin
arun_p211-Jan-11 23:50
arun_p211-Jan-11 23:50 
GeneralVB2008 Synchonization of scroll bars Pin
Rolfo112-May-10 10:29
Rolfo112-May-10 10:29 
GeneralRe: VB2008 Synchonization of scroll bars Pin
progload13-May-10 5:45
progload13-May-10 5:45 
GeneralC# synched scrolling with 65536 pixels limit resolved Pin
Cyggy31-Mar-10 11:51
Cyggy31-Mar-10 11:51 
QuestionHow to change this code to Visual C++ Whidbey? Pin
chrisliando18-Feb-08 22:26
chrisliando18-Feb-08 22:26 
Generalvery simple solution Pin
tipiceberg18-Dec-07 13:47
susstipiceberg18-Dec-07 13:47 
QuestionCan you compile and run this code in vs 2005? Pin
followthesun4-Jan-07 6:25
followthesun4-Jan-07 6:25 
Generalprogload, does your solution still work if RichTextBox is replaced with Panel Pin
jgyie222-Aug-06 19:03
jgyie222-Aug-06 19:03 
Generallot easier Pin
tom-joad24-Mar-06 3:22
tom-joad24-Mar-06 3:22 
AnswerScrolling Test Code for VB2005 Pin
progload24-Feb-06 10:31
progload24-Feb-06 10:31 
GeneralRe: C# 2005 Version Pin
RedPhoenix.net13-Jun-06 15:08
RedPhoenix.net13-Jun-06 15:08 
NewsA simpler solution... Pin
boneheadIII4-Nov-05 5:49
boneheadIII4-Nov-05 5:49 
GeneralRe: A simpler solution... Pin
progload4-Nov-05 15:32
progload4-Nov-05 15:32 
GeneralMy system shows error on your code Pin
vaibhav tiwari25-Oct-05 7:34
vaibhav tiwari25-Oct-05 7:34 
GeneralCode was originaly written for .Net 1.1 Pin
progload4-Nov-05 15:28
progload4-Nov-05 15:28 
Questionget height of contents? Pin
frumbert14-Aug-05 15:32
frumbert14-Aug-05 15:32 
AnswerRe: get height of contents? Pin
progload15-Aug-05 18:52
progload15-Aug-05 18:52 
Generaldoes not work with VB.net 2005 (2.0 framework) Pin
Member 154214421-Jun-05 8:12
Member 154214421-Jun-05 8:12 
GeneralRe: does not work with VB.net 2005 (2.0 framework) Pin
progload4-Nov-05 15:38
progload4-Nov-05 15:38 
GeneralC++ Code Pin
yy67820-Apr-05 2:17
yy67820-Apr-05 2:17 
GeneralRe: C++ Code Pin
progload20-Apr-05 18:43
progload20-Apr-05 18:43 
GeneralC# Code - Thanks to theRealCondor Pin
progload3-Oct-04 10:17
progload3-Oct-04 10:17 
I noticed Today that theRealCondor has posted a C# version here in the forum.
http://www.codeproject.com/script/comments/forums.asp?forumid=1649&select=912488&df=100&fr=2496.5#xx912488xx

Thanks again, for the work theRealCondor.

progload.

here it is again.

C#
using System;
using System.IO;
using System.Data;
using System.Text;
using System.Drawing;
using System.Collections;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace TestMultiScroll 
{
	public class Form1 : System.Windows.Forms.Form 
	{
		private System.ComponentModel.IContainer components = null;
		public System.Windows.Forms.RichTextBox RichTextBox1 = null;
		public System.Windows.Forms.RichTextBox RichTextBox2 = null;
		public System.Windows.Forms.RichTextBox RichTextBox3 = null;

		// ===================================================================
		// for NativeWindow and PostMessageA
		// =================================================================== 
		private const int WM_HSCROLL = 0x114;
		private const int WM_VSCROLL = 0x115;
		private const int WM_MOUSEWHEEL = 0x20A;
		private const int WM_COMMAND = 0x111;
		// ===================================================================
		// for GetScroll and PostMessageA
		// =================================================================== 
		private const int WM_USER = 0x400;
		private const int SBS_HORZ = 0;
		private const int SBS_VERT = 1;
		// ===================================================================
		// for SubClassing
		// =================================================================== 
		private const int SB_THUMBPOSITION = 4;
		private Subclass sClass1 = null;
		private Subclass sClass2 = null;
		private Subclass sClass3 = null;


		public Form1()
		{
			InitializeComponent();
		}

		protected void Dispose(bool disposing) 
		{
			if (disposing) 
			{
				if ( !( (components == null))) 
				{
					components.Dispose();
				}
			}
			base.Dispose(disposing);
		}

		#region Windows Form Designer generated code
		private void InitializeComponent() 
		{
			this.RichTextBox1 = new System.Windows.Forms.RichTextBox ();
			this.RichTextBox2 = new System.Windows.Forms.RichTextBox ();
			this.RichTextBox3 = new System.Windows.Forms.RichTextBox ();
			this.SuspendLayout();
			// 
			// RichTextBox1
			// 
			this.RichTextBox1.Location = new System.Drawing.Point (24, 24);
			this.RichTextBox1.Name = "RichTextBox1";
			this.RichTextBox1.Size = new System.Drawing.Size (128, 128);
			this.RichTextBox1.TabIndex = 0;
			this.RichTextBox1.Text = "RichTextBox1";
			this.RichTextBox1.WordWrap = false;
			// 
			// RichTextBox2
			// 
			this.RichTextBox2.Location = new System.Drawing.Point (160, 24);
			this.RichTextBox2.Name = "RichTextBox2";
			this.RichTextBox2.Size = new System.Drawing.Size (128, 128);
			this.RichTextBox2.TabIndex = 1;
			this.RichTextBox2.Text = "RichTextBox2";
			this.RichTextBox2.WordWrap = false;
			// 
			// RichTextBox3
			// 
			this.RichTextBox3.Location = new System.Drawing.Point (296, 24);
			this.RichTextBox3.Name = "RichTextBox3";
			this.RichTextBox3.Size = new System.Drawing.Size (128, 128);
			this.RichTextBox3.TabIndex = 3;
			this.RichTextBox3.Text = "RichTextBox3";
			this.RichTextBox3.WordWrap = false;
			// 
			// Form1
			// 
			this.AutoScaleBaseSize = new System.Drawing.Size (5, 13);
			this.ClientSize = new System.Drawing.Size (448, 174);
			this.Controls.Add(this.RichTextBox3);
			this.Controls.Add(this.RichTextBox2);
			this.Controls.Add(this.RichTextBox1);
			this.Name = "Form1";
			this.Text = "Form1";
			this.ResumeLayout(false);
			this.Load += new System.EventHandler (Form1_Load);

			this.RichTextBox1.VScroll += new System.EventHandler (RichTextBox1_VScroll);
			this.RichTextBox2.VScroll += new System.EventHandler (RichTextBox2_VScroll);
			this.RichTextBox3.VScroll += new System.EventHandler (RichTextBox3_VScroll);
			this.RichTextBox1.HScroll += new System.EventHandler (RichTextBox1_HScroll);
			this.RichTextBox2.HScroll += new System.EventHandler (RichTextBox2_HScroll);
			this.RichTextBox3.HScroll += new System.EventHandler (RichTextBox3_HScroll);
		}
		#endregion

		/// 
		/// The main entry point for the application.
		/// 
		[STAThread]
		static void Main() 
		{
			Application.Run(new Form1());
		}

		private void Form1_Load(System.Object sender,System.EventArgs e) 
		{
			sClass1 = new Subclass(RichTextBox1.Handle);
			sClass2 = new Subclass(RichTextBox2.Handle);
			sClass3 = new Subclass(RichTextBox3.Handle);
			this.sClass1.NativeWindowsEvent += new Subclass.WindowsEventHandler (sClass_WindowProcedure);
			this.sClass2.NativeWindowsEvent += new Subclass.WindowsEventHandler (sClass_WindowProcedure);
			this.sClass3.NativeWindowsEvent += new Subclass.WindowsEventHandler (sClass_WindowProcedure);

			for (int i = 0; i <= 100; i++)
			{
				if (i % 4 == 0) 
				{
					RichTextBox1.AppendText(" this is a longer string to force HScroll " + i + System.Environment.NewLine);
					RichTextBox2.AppendText(" this is a longer string to force HScroll " + i + System.Environment.NewLine);
					RichTextBox3.AppendText(" this is a longer string to force HScroll " + i + System.Environment.NewLine);
				}
				else 
				{
					RichTextBox1.AppendText(" this is a string " + i + System.Environment.NewLine);
					RichTextBox2.AppendText(" this is a string " + i + System.Environment.NewLine);
					RichTextBox3.AppendText(" this is a string " + i + System.Environment.NewLine);
				}
			}
		}

		public void sClass_WindowProcedure(ref Message uMsg) 
		{
			switch (uMsg.Msg) 
			{
				case (WM_VSCROLL):
					if (uMsg.HWnd.Equals(RichTextBox1.Handle)) 
					{
						ThumbScrollHandler(RichTextBox1, new RichTextBox[] {RichTextBox2, RichTextBox3}, ref uMsg);
					}
					if (uMsg.HWnd.Equals(RichTextBox2.Handle)) 
					{
						ThumbScrollHandler(RichTextBox2, new RichTextBox[] {RichTextBox1, RichTextBox3}, ref uMsg);
					}
					if (uMsg.HWnd.Equals(RichTextBox3.Handle)) 
					{
						ThumbScrollHandler(RichTextBox3, new RichTextBox[] {RichTextBox1, RichTextBox2}, ref uMsg);
					}
					break;
				case (WM_HSCROLL):
					if (uMsg.HWnd.Equals(RichTextBox1.Handle)) 
					{
						ThumbScrollHandler(RichTextBox1, new RichTextBox[] {RichTextBox2, RichTextBox3}, ref uMsg);
					}
					if (uMsg.HWnd.Equals(RichTextBox2.Handle)) 
					{
						ThumbScrollHandler(RichTextBox2, new RichTextBox[] {RichTextBox1, RichTextBox3}, ref uMsg);
					}
					if (uMsg.HWnd.Equals(RichTextBox3.Handle)) 
					{
						ThumbScrollHandler(RichTextBox3, new RichTextBox[] {RichTextBox1, RichTextBox2}, ref uMsg);
					}
					break;
			}
		}

		private void ThumbScrollHandler(RichTextBox sender, RichTextBox[] receivers, ref Message uMsg)
		{
			sClass2.NativeWindowsEvent -= new Subclass.WindowsEventHandler(ref sClass_WindowProcedure);
			foreach (RichTextBox receiver in receivers)
			{
				Message msg = Message.Create(receiver.Handle, uMsg.Msg, uMsg.WParam, uMsg.LParam);
				sClass2.SendWndProc(ref msg);
			}
			sClass2.NativeWindowsEvent += new Subclass.WindowsEventHandler(ref sClass_WindowProcedure);
		}
		private void RichTextBox1_VScroll(object sender,System.EventArgs e) 
		{
			VerticalScroll(RichTextBox1, new RichTextBox[2] {RichTextBox2, RichTextBox3});
		}

		private void RichTextBox2_VScroll(object sender,System.EventArgs e) 
		{
			VerticalScroll(RichTextBox2, new RichTextBox[2] {RichTextBox1, RichTextBox3});
		}

		private void RichTextBox3_VScroll(object sender,System.EventArgs e) 
		{
			VerticalScroll(RichTextBox3, new RichTextBox[2] {RichTextBox1, RichTextBox2});
		}

		private void RichTextBox1_HScroll(object sender,System.EventArgs e) 
		{
			HorizontalScroll(RichTextBox1, new RichTextBox[2] {RichTextBox2, RichTextBox3});
		}

		private void RichTextBox2_HScroll(object sender,System.EventArgs e) 
		{
			HorizontalScroll(RichTextBox2, new RichTextBox[2] {RichTextBox1, RichTextBox3});
		}

		private void RichTextBox3_HScroll(object sender,System.EventArgs e) 
		{
			HorizontalScroll(RichTextBox3, new RichTextBox[2] {RichTextBox1, RichTextBox2});
		}

		private void VerticalScroll(RichTextBox sender, RichTextBox[] receivers)
		{
			int position = GetScrollPos(sender.Handle, SBS_VERT);
			foreach (RichTextBox receiver in receivers)
			{
				PostMessageA(receiver.Handle, WM_VSCROLL, SB_THUMBPOSITION + 0x10000 * position, 0);
			}

		}
		private void HorizontalScroll(RichTextBox sender, RichTextBox[] receivers)
		{
			int position = GetScrollPos(sender.Handle, SBS_HORZ);
			foreach(RichTextBox receiver in receivers)
			{
				PostMessageA(receiver.Handle, WM_HSCROLL, SB_THUMBPOSITION + 0x10000 * position, 0);
			}
		}
		// ===================================================================
		// API Function: GetScrollPos()
		// =================================================================== 
		[DllImport("user32.dll")]
		private static extern int GetScrollPos(IntPtr hWnd, int nBar); 
		// ===================================================================
		// API Function: PostMessageA()
		// =================================================================== 
		[DllImport("user32.dll")]
		private static extern bool PostMessageA(IntPtr hwnd, int wMsg, int wParam, int lParam); 
	}

	// ===================================================================
	// NativeWindow Subclassing
	// =================================================================== 
	public class Subclass : System.Windows.Forms.NativeWindow 
	{
		public event WindowsEventHandler NativeWindowsEvent;
		public delegate void WindowsEventHandler(ref Message uMsg);
		public Subclass(IntPtr pWindowHandle):base()
		{
			base.AssignHandle(pWindowHandle);
		}

		protected override void WndProc(ref System.Windows.Forms.Message uMsg)
		{
			base.WndProc(ref uMsg);
			if (NativeWindowsEvent != null)
				NativeWindowsEvent(ref uMsg);
		}

		public void SendWndProc(ref System.Windows.Forms.Message uMsg)
		{
			base.WndProc(ref uMsg);
		}
	}
}

GeneralUpdate Pin
progload13-Aug-04 12:46
progload13-Aug-04 12:46 
GeneralMinor Bug : Updation if ScrollBar Thumb Pin
Jay Shankar1-Aug-04 23:25
Jay Shankar1-Aug-04 23:25 
GeneralRe: Minor Bug : Updation if ScrollBar Thumb Pin
progload2-Aug-04 8:04
progload2-Aug-04 8:04 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.