2009-12-05 5 views
12

Ich habe eine Listenansicht, die Miniaturansicht mit einem Hintergrundarbeiter generiert. Wenn die Listenansicht gescrollt wird, möchte ich den Hintergrundarbeiter pausieren und den aktuellen Wert des gescrollten Bereichs erhalten. Wenn der Benutzer den Listenblick nicht mehr durchsucht hat, setze den Hintergrundarbeiter beginnend mit dem Element entsprechend dem Wert des gescrollten Bereichs fort.Umgang mit Scroll-Ereignis in Listview in C#

Ist es möglich, Scroll-Ereignis eines Listview zu behandeln? wenn ja wie? Wenn nicht, was ist dann eine gute Alternative nach dem, was ich oben beschrieben habe?

Antwort

16

Sie müssen der ListView-Klasse Unterstützung hinzufügen, damit Sie über Scroll-Ereignisse benachrichtigt werden können. Fügen Sie Ihrem Projekt eine neue Klasse hinzu und fügen Sie den folgenden Code ein. Kompilieren. Legen Sie das neue ListView-Steuerelement oben in der Toolbox auf Ihr Formular ab. Implementieren Sie einen Handler für das neue Scroll-Ereignis.

using System; 
using System.Windows.Forms; 

    class MyListView : ListView { 
     public event ScrollEventHandler Scroll; 
     protected virtual void OnScroll(ScrollEventArgs e) { 
     ScrollEventHandler handler = this.Scroll; 
     if (handler != null) handler(this, e); 
     } 
     protected override void WndProc(ref Message m) { 
     base.WndProc(ref m); 
     if (m.Msg == 0x115) { // Trap WM_VSCROLL 
      OnScroll(new ScrollEventArgs((ScrollEventType)(m.WParam.ToInt32() & 0xffff), 0)); 
     } 
     } 
    } 

Beachten Sie, dass die Scroll-Position (ScrollEventArgs.NewValue) nicht sinnvoll ist, es hängt von der Anzahl der Elemente in der Listview. Ich habe es auf 0 gesetzt. Nach Ihren Anforderungen sollten Sie darauf achten, dass die ScrollEventType.EndScroll-Benachrichtigung weiß, wann der Benutzer den Bildlauf angehalten hat. Alles andere hilft Ihnen zu erkennen, dass der Benutzer mit dem Scrollen begonnen hat. Zum Beispiel:

ScrollEventType mLastScroll = ScrollEventType.EndScroll; 

private void myListView1_Scroll(object sender, ScrollEventArgs e) { 
    if (e.Type == ScrollEventType.EndScroll) scrollEnded(); 
    else if (mLastScroll == ScrollEventType.EndScroll) scrollStarted(); 
    mLastScroll = e.Type; 
} 
+0

vielen Dank nobugz. Genau das versuche ich zu erreichen. – murasaki5

+3

Lesen Sie http://stackoverflow.com/questions/1176703/listview-onscroll-event/1182232#1182232, um einige Einschränkungen mit der WM_VSCROLL-Nachricht anzuzeigen. – Grammarian

+0

Diese Antwort hat einen fiesen Bug auf Net Framework 2.0 mit Gitternetzlinien behoben – Mandrake

1

finden Sie in diesem Beitrag ListView Scroll Event

Verwenden Sie die nativen Fensterklasse für die Scroll-Nachrichten auf dem listbox zu hören. Arbeitet mit jeder Kontrolle.

+0

Basierend auf der Post, die @Adriaan Stander gepostet meine Klasse zum Anheben von Scroll-Events ist unten. http://Stackoverflow.com/a/35645892/254215 – Dib

0

das Scroll-Ereignis jetzt fängt leicht in .net 4.

Catch the Loaded-Ereignis aus dem Listview (m_ListView) und tut dies geschehen ist:

 if (VisualTreeHelper.GetChildrenCount(m_ListView) != 0) 
     { 
      Decorator border = VisualTreeHelper.GetChild(m_ListView, 0) as Decorator; 
      ScrollViewer sv = border.Child as ScrollViewer; 
      sv.ScrollChanged += ScrollViewer_ScrollChanged; 
     } 

dann, implementieren Ihre ScrollViewer_ScrollChanged Funktion:

private void ScrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e) 
    { 
     ... 
    } 
+1

Dies ist für WPF. Nützliche Informationen, aber die Frage ist für Windows-Formulare. – flobadob

0

Basierend auf dem Pfosten, der @Adriaan Stander poste d Meine Klasse zum Erhöhen der Scroll-Ereignisse ist unten.

internal class ControlScrollListener : NativeWindow, IDisposable 
{ 
    public event ControlScrolledEventHandler ControlScrolled; 
    public delegate void ControlScrolledEventHandler(object sender, EventArgs e); 

    private const uint WM_HSCROLL = 0x114; 
    private const uint WM_VSCROLL = 0x115; 
    private readonly Control _control; 

    public ControlScrollListener(Control control) 
    { 
     _control = control; 
     AssignHandle(control.Handle); 
    } 

    protected bool Disposed { get; set; } 

    public void Dispose() 
    { 
     Dispose(true); 
     GC.SuppressFinalize(this); 
    } 

    private void Dispose(bool disposing) 
    { 
     if (Disposed) return; 

     if (disposing) 
     { 
      // Free other managed objects that implement IDisposable only 
     } 

     // release any unmanaged objects 
     // set the object references to null 
     ReleaseHandle(); 

     Disposed = true; 
    } 

    protected override void WndProc(ref Message m) 
    { 
     HandleControlScrollMessages(m); 
     base.WndProc(ref m); 
    } 

    private void HandleControlScrollMessages(Message m) 
    { 
     if (m.Msg == WM_HSCROLL | m.Msg == WM_VSCROLL) 
     { 
      if (ControlScrolled != null) 
      { 
       ControlScrolled(_control, new EventArgs()); 
      } 
     } 
    } 
} 

Verwenden Sie es wie so ...

Deklarieren Sie ein Feld:

private ControlScrollListener _processListViewScrollListener; 

es mit den Kontrollen Instantiate, die Sie wissen müssen, issrolling:

_processListViewScrollListener = new ControlScrollListener(ProcessesListView); 

Hautnah ein Handler:

_processListViewScrollListener.ControlScrolled += ProcessListViewScrollListener_ControlScrolled; 

Handler die Veranstaltung:

void ProcessListViewScrollListener_ControlScrolled(object sender, EventArgs e) 
{ 
    // do what you need to do 
} 

Die Veranstaltung args im Falle angehoben könnten weitere nützliche Informationen enthalten werden gezwickt. Ich musste nur wissen, dass meine Kontrolle gescrollt wurde!

+0

Handelt nicht mit Mausrad scrollen. Muss die Bildlaufleiste verwenden. Müssen Sie 'private const uint WM_MOUSEWHEEL = 0x020A;' hinzufügen, wenn Sie das wollen. – rism