2010-09-29 14 views
14

Jak zsynchronizować przewijanie dwóch wieloliniowych pól tekstowych w języku C# (WinForm)?Jak mogę zsynchronizować przewijanie dwóch multilinicznych pól tekstowych?

Podczas przewijania w górę/w dół linii w TextBox A, TextBox B powinien również przewijać w górę/w dół. To samo na odwrót.

Czy jest to możliwe bez niestandardowych elementów sterujących?

+0

Nie można odpowiedzieć, chyba że poinformujesz nas, jakiego rodzaju framework GUI używasz. – mikerobi

+0

Po prostu domyślne WinForm. – lesderid

Odpowiedz

34

Tak, musisz utworzyć niestandardowe pole tekstowe, aby można było je przewijać. Sztuką jest przekazanie wiadomości przewijania do drugiego pola tekstowego, aby było przewijane zsynchronizowane. To naprawdę działa tylko wtedy, gdy inne pole tekstowe ma mniej więcej taki sam rozmiar i ma taką samą liczbę linii.

Dodaj nową klasę do swojego projektu i wklej poniższy kod. Skompilować. Rzuć dwie nowe kontrolki z góry przybornika na formularz. Ustaw właściwość Buddy na drugą kontrolę w obu. Uruchom, wpisz tekst w obu z nich i obserwuj ich przewijanie zsynchronizowane podczas przeciągania paska przewijania.

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

Awesome, Thanks! – lesderid

+1

To jest cud !!!! –

+0

@Hans Passant: chciałem osiągnąć podobne, ale w przypadku dwóch widoków listy. próbowałem używać tego kodu, ale nie działa. czy muszę coś w tym dodać? –

8

Można zmienić tę linię:

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

do tego:

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

i będzie wspierać przewijanie kółkiem myszy, jak również.

+0

dziękuję za to, to było niesamowicie pomocne – eruciform

+0

Niestety, chociaż wydaje się, że działa, przewijanie staje się niezsynchronizowane z kółkiem myszy, a główny tekst jest przewijany szybciej niż kolega. – SurfingSanta

+0

Co się stanie, gdy przeciągniesz suwak przewijania i lewy przycisk myszy, przesuwasz suwak w górę iw dół, a widok listy znajomych nie reaguje na przewijanie? –

2

Rozwiązanie Hans Passant działało jak urok, ale potrzebowałem RichTextBox z poziomymi i pionowymi paskami przewijania. Jeśli rozszerzasz RichTextBox zamiast TextBox, będziesz musiał odpowiednio zmienić właściwość ScrollBars (użyłem RichTextBoxScrollBars.Both).

Aby zsynchronizować również przewijanie w poziomie, poszukaj (m.Msg == 0x115) || (m.Msg == 0x114).

3

Rozwiązanie Hans Passant było niesamowite. Jednak potrzebowałem zsynchronizować trzy pola tekstowe nie tylko dwa.

Więc trochę go zmodyfikowałem - ale cała wiara powinna trafić do Hansa, nie ma mowy, bym się zbliżył bez jego pracy - myślałem, że wrócę tutaj, na wypadek, gdyby inni potrzebowali tego samego.

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

Następnie w initilizer forma:

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

Oto co w końcu pomógł mi naprawić synchronizację wielu tekstowych z użyciem kółka myszy.

Oparłem to na bardzo przydatnym przykładzie Hansa.

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); 
} 
Powiązane problemy