2009-12-01 40 views
15

Trong mẫu đơn của tôi, tôi có hai đối tượng RichTextBox. Cả hai sẽ luôn có cùng số dòng văn bản. Tôi muốn "đồng bộ hóa" di chuyển dọc giữa hai thứ này, để khi người dùng thay đổi vị trí cuộn dọc trên một, người kia cuộn cùng một lượng. Làm thế nào tôi có thể đi về việc này?C#: Đồng bộ hóa vị trí cuộn của hai RichTextBoxes?

Trả lời

15

Tôi đã làm điều này cho một dự án nhỏ một thời gian trước đây và đây là giải pháp đơn giản mà tôi đã tìm thấy.

Tạo một điều khiển mới bằng cách subclassing 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); 
     } 
    }  

Thêm điều khiển mới để hình của bạn và cho mỗi điều khiển thông báo một cách rõ ràng trường hợp khác của điều khiển vị trí vScroll của nó đã thay đổi. Mọi thứ như thế này:

private void scrollSyncTxtBox1_vScroll(Message msg) { 
    msg.HWnd = scrollSyncTxtBox2.Handle; 
    scrollSyncTxtBox2.PubWndProc(ref msg); 
} 

Tôi nghĩ mã này có vấn đề nếu tất cả các điều khiển 'được liên kết' không có cùng số dòng hiển thị.

+0

Phương pháp này hoạt động tốt để cuộn bằng cách di chuyển thanh cuộn. Nhưng các thanh cuộn không được đồng bộ khi (1) cuộn bằng bánh xe chuột (2) di chuyển bằng phím 'page down' hoặc' page up' - cuộn bằng cách nhấn các phím mũi tên – twnaing

+0

@Jay riggs 'System.Windows.Forms.RichTextBox' không chứa định nghĩa cho 'PubWndProc' và không có phương thức mở rộng 'PubWndProc' chấp nhận đối số đầu tiên của loại 'System.Windows.Forms.RichTextBox' có thể được tìm thấy (bạn đang thiếu một chỉ thị sử dụng hoặc tham chiếu assembly?) – Pomster

18

Xin cảm ơn Jay vì câu trả lời của bạn; sau khi tìm kiếm thêm, tôi cũng tìm thấy phương pháp được mô tả here. Tôi sẽ phác thảo nó bên dưới cho bất kỳ ai quan tâm.


Thứ nhất, tuyên bố enums sau:

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 
} 

Tiếp theo, thêm tài liệu tham khảo bên ngoài để 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); 

Cuối cùng, thêm một event handler cho sự kiện VScroll của thích hợp RichTextBox:

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

Trong trường hợp này, vị trí cuộn dọc richTextBox2 's sẽ được đồng bộ với richTextBox1.

+0

Tóm tắt tuyệt vời . Tiết kiệm rất nhiều thời gian của tôi. Cảm ơn bạn! –

+1

mã hex cho WM_HSCROLL là gì? – Logerfo

1

Một biến thể của cách tiếp cận phân lớp của Jay có thể được tìm thấy trong bài đăng của Joseph Kingry ở đây: Synchronizing Multiline Textbox Positions in C#. Cách tiếp cận của Joseph cũng là lớp con nhưng không yêu cầu trình xử lý sự kiện _VScroll. Tôi đã sử dụng cách tiếp cận đó để thực hiện liên kết 3 chiều giữa 3 hộp và thêm WM_HSCROLL.

3

[Visual Studio C# 2010 Express, v10.0.30319 trên Windows cài đặt 7 64bit]

Tôi đã sử dụng giải pháp Donut của posted ở trên, nhưng không tìm thấy một vấn đề khi di chuyển đến cuối RichTextBoxes có chứa nhiều đường.

Nếu kết quả của GetScrollPos()>0x7FFF thì khi chuyển đổi nPos, bit trên cùng được đặt. Việc tạo IntPtr với biến số wParam kết quả sau đó sẽ không thành công với số OverflowException. Bạn có thể dễ dàng kiểm tra này như sau (dòng thứ hai sẽ thất bại):

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

Một phiên bản của SendMessage() sử dụng UIntPtr sẽ xuất hiện như một giải pháp, nhưng tôi không thể nhận được rằng để làm việc.Vì vậy, tôi đã sử dụng các mục sau:

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

Điều này sẽ tốt cho đến 0xffff, nhưng sẽ không thành công sau đó. Tôi chưa trải qua một kết quả >0xffff từ GetScrollPos() và giả sử rằng User32.dll không có phiên bản 64 bit là SendCommand(), nhưng mọi giải pháp cho vấn đề đó sẽ được đánh giá rất nhiều.

Các vấn đề liên quan