Detectando cuando la barra de desplazamiento ListView llega al final

¿Cómo puedo saber cuando la barra de desplazamiento de WinForms ListView llega al final?

Cuando esto suceda, quiero que la vista de lista se llene con más datos (que en teoría es interminable en mi caso).

El evento OnScroll me da el valor de desplazamiento desde la parte superior, pero no tengo forma de saber si el usuario puede desplazarse más o no.

preguntado el 16 de mayo de 11 a las 19:05

3 Respuestas

Encontré una respuesta usando un código del gran proyecto de código ObjectListView: http://www.codeproject.com/KB/list/ObjectListView.aspx

llamar a GetScrollInfo:

    private const int SIF_RANGE = 0x0001;
    private const int SIF_PAGE = 0x0002;
    private const int SIF_POS = 0x0004;
    private const int SIF_DISABLENOSCROLL = 0x0008;
    private const int SIF_TRACKPOS = 0x0010;
    private const int SIF_ALL = (SIF_RANGE | SIF_PAGE | SIF_POS | SIF_TRACKPOS);        
    private const int SB_HORZ = 0;
    private const int SB_VERT = 1;

    [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
    public static extern bool GetScrollInfo(IntPtr hWnd, int fnBar, SCROLLINFO scrollInfo);

    public static SCROLLINFO GetFullScrollInfo(ListView lv, bool horizontalBar) {
      int fnBar = (horizontalBar ? SB_HORZ : SB_VERT);

      SCROLLINFO scrollInfo = new SCROLLINFO();
      scrollInfo.fMask = SIF_ALL;
      if (GetScrollInfo(lv.Handle, fnBar, scrollInfo))
        return scrollInfo;
      else
        return null;
    }

con esta estructura de datos:

    [StructLayout(LayoutKind.Sequential)]
    public class SCROLLINFO
    {
        public int cbSize = Marshal.SizeOf(typeof(SCROLLINFO));
        public int fMask;
        public int nMin;
        public int nMax;
        public int nPage;
        public int nPos;
        public int nTrackPos;
    }

nMax da el valor de desplazamiento máximo total, incluido el controlador de desplazamiento en sí, por lo que el valor máximo realmente útil es nMax - nPage, donde nPage es el tamaño del controlador de desplazamiento.

¡Esto funciona muy bien!

Respondido 16 ago 16, 05:08

No puedo responder a su pregunta directamente, pero a partir de su descripción, parece que realmente desea considerar el uso del modo virtual de una vista de lista para administrar un gran conjunto de datos.

http://msdn.microsoft.com/en-us/library/system.windows.forms.listview.virtualmode.aspx

contestado el 16 de mayo de 11 a las 23:05

El modo virtual puede ser inteligente por sí solo en este caso, pero no resolverá mi problema. Mis datos son infinitos (es una vista de lista de fechas), por lo que no puedo mostrar una vista de lista enorme con millones de filas hasta 2100 (?). Necesito que la lista crezca cuando el usuario llegue al final. - Adams

En el caso de que alguien necesite esto, tomo prestado el código anterior y mejoré un poco para manejar el evento onMaximumBottomScroll usando el teclado con las teclas hacia abajo, página siguiente y final, arrastrando o haciendo clic en la barra de desplazamiento y alcanzando la parte inferior máxima, y ​​usando la rueda del mouse en vertical u horizontalmente. Esto me está funcionando a las mil maravillas.

 public partial class OrganizationFilesListView : ListView
{
    // Windows messages
    private const int WM_VSCROLL = 0x0115;
    private const int WM_MOUSEHWHEEL = 0x020E;
    private const int WM_MOUSEWHEEL = 0x020A;
    private const int WM_KEYDOWN = 0x0100;

    // ScrollBar types
    private const int SB_VERT = 1; // only for maximum vertical scroll position

    // ScrollBar interfaces
    private const int SIF_TRACKPOS = 0x10;
    private const int SIF_RANGE = 0x01;
    private const int SIF_POS = 0x04;
    private const int SIF_PAGE = 0x02;
    private const int SIF_ALL = SIF_RANGE | SIF_PAGE | SIF_POS | SIF_TRACKPOS;

    // variable to force to run only once the event
    private bool runningOnMaximumBottomScroll = false;

    protected override void WndProc(ref Message m)
    {
        base.WndProc(ref m);
        SCROLLINFO si = new SCROLLINFO();
        si.cbSize = (uint)Marshal.SizeOf(si);
        si.fMask = (uint)ScrollInfoMask.SIF_ALL;
        bool isMaximumButtomScroll = false;

        switch (m.Msg)
        {
            case WM_VSCROLL:
                isMaximumButtomScroll = GetScrollInfo(m.HWnd, SB_VERT, ref si) ? (si.nPage + si.nPos) >= si.nMax : false;
                if (isMaximumButtomScroll && !runningOnMaximumBottomScroll)
                {
                    runningOnMaximumBottomScroll = true;
                    onMaximumBottomScroll(this, new ScrollEventArgs(ScrollEventType.EndScroll, GetScrollPos(this.Handle, SB_VERT)));
                    runningOnMaximumBottomScroll = false;
                }
                break;
            case WM_MOUSEHWHEEL:
            case WM_MOUSEWHEEL:
                isMaximumButtomScroll = GetScrollInfo(m.HWnd, SB_VERT, ref si) ? (si.nPage + si.nPos) >= si.nMax : false;
                bool isMouseWheelDown = m.Msg == WM_MOUSEWHEEL ? (int)m.WParam < 0 : (int)m.WParam > 0;
                if (isMaximumButtomScroll && isMouseWheelDown && !runningOnMaximumBottomScroll)
                {
                    runningOnMaximumBottomScroll = true;
                    onMaximumBottomScroll(this, new ScrollEventArgs(ScrollEventType.EndScroll, GetScrollPos(this.Handle, SB_VERT)));
                    runningOnMaximumBottomScroll = false;
                }
                break;
            case WM_KEYDOWN:
                isMaximumButtomScroll = GetScrollInfo(m.HWnd, SB_VERT, ref si) ? (si.nPage + si.nPos) >= (si.nMax - 1) : false;
                switch (m.WParam.ToInt32())
                {
                    case (int)Keys.Down:
                    case (int)Keys.PageDown:
                    case (int)Keys.End:
                        if (isMaximumButtomScroll && !runningOnMaximumBottomScroll)
                        {
                            runningOnMaximumBottomScroll = true;
                            onMaximumBottomScroll(this, new ScrollEventArgs(ScrollEventType.EndScroll, GetScrollPos(this.Handle, SB_VERT)));
                            runningOnMaximumBottomScroll = false;
                        }
                        break;
                }
                break;
        }
    }

    public event ScrollEventHandler onMaximumBottomScroll;

    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool GetScrollInfo(IntPtr hwnd, int fnBar, ref SCROLLINFO lpsi);

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    static extern int GetScrollPos(IntPtr hWnd, int nBar);

    [Serializable, StructLayout(LayoutKind.Sequential)]
    struct SCROLLINFO
    {
        public uint cbSize;
        public uint fMask;
        public int nMin;
        public int nMax;
        public uint nPage;
        public int nPos;
        public int nTrackPos;
    }

    public enum ScrollInfoMask : uint
    {
        SIF_RANGE = 0x1,
        SIF_PAGE = 0x2,
        SIF_POS = 0x4,
        SIF_DISABLENOSCROLL = 0x8,
        SIF_TRACKPOS = 0x10,
        SIF_ALL = (SIF_RANGE | SIF_PAGE | SIF_POS | SIF_TRACKPOS),
    }
}

Listo ... disfrútalo!

Respondido el 11 de Septiembre de 19 a las 08:09

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.