2010-09-29 97 views
14

如何同步C#(WinForms)中兩個多行文本框的滾動?如何同步兩個多行文本框的滾動?

當您在文本框A中向上/向下滾動一行時,文本框B也應該向上/向下滾動。 相反的方式。

這可以實現沒有自定義控件?

+0

除非您告訴我們您正在使用的GUI框架類型,否則無法回答。 – mikerobi 2010-09-29 15:40:07

+0

只是默認的WinForms。 – lesderid 2010-09-29 15:42:11

回答

34

是的,你必須創建一個自定義文本框,以便你可以檢測到它滾動。訣竅是將滾動消息傳遞給其他文本框,以便它將同步滾動。當其他文本框的大小相同並具有相同的行數時,這真的只適用於其他文本框。

向您的項目中添加一個新類並粘貼下面顯示的代碼。編譯。將工具箱頂部的兩個新控件放到表單上。將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); 
} 
+1

真棒,謝謝! – lesderid 2010-09-29 15:54:36

+1

這是奇蹟!!!! – 2011-12-08 09:08:31

+0

@Hans Passant:我想實現類似的,但在兩個列表視圖的情況下。我試過使用這個代碼,但它不工作。我需要在這添加一些東西嗎? – 2013-02-06 10:56:13

8

你可以改變這一行:

if (m.Msg == 0x115) && !scrolling && Buddy != null && Buddy.IsHandleCreated) 

這樣:

if ((m.Msg == 0x115 || m.Msg==0x20a) && !scrolling && Buddy != null && Buddy.IsHandleCreated) 

,它將支持使用鼠標滾輪滾動的爲好。

+0

感謝你這一點,這是難以置信的幫助 – eruciform 2013-04-11 19:21:28

+0

不幸的是,雖然這似乎工作,滾動失控鼠標滾輪同步的,而且比好友更快的主要文本框滾動。 – SurfingSanta 2016-08-22 01:33:31

+0

怎麼樣當你拖動滾動滑動和鼠標左鍵按下你滑動上下滑動,他們的好友列表視圖不會對滾動作出反應? – 2018-01-24 19:14:30

2

Hans Passant的解決方案像一個魅力工作,但我需要一個RichTextBox水平和垂直滾動條。如果擴展RichTextBox而不是TextBox,則需要相應地更改ScrollBars屬性(我使用RichTextBoxScrollBars.Both)。

如果您想同步水平滾動,請查找(m.Msg == 0x115) || (m.Msg == 0x114)

3

Hans Passant的解決方案非常棒。不過,我需要同步三個文本框,而不僅僅是兩個。

所以我修改了一下 - 但所有的信任都應該去漢斯,沒有他的工作我就沒有辦法關閉它 - 我想我會在這裏發佈它,以防其他人需要相同的東西。

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

然後在表格initilizer:

// add the required controls into scroll sync 
Control[] syncedCtrls = new Control[] { ctrl1, ctrl2, ..., ctrln }; 
foreach (SyncTextBox ctr in syncedCtrls) 
{ 
    ctr.Buddies = syncedCtrls; 
} 
0

這裏是終於幫我解決使用鼠標滾輪多個文本框的同步。

我基於非常有用的漢斯例子。

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