检测ListView滚动条何时到达WinForms的底部

时间:2011-05-16 19:10:00

标签: c# .net winforms

如何知道WinForms ListView滚动条何时到达底部? 当发生这种情况时,我希望列表视图中填充更多数据(在我的情况下,这在理论上是无穷无尽的。)

OnScroll事件从顶部给出了滚动值,但我无法知道用户是否可以进一步滚动。

3 个答案:

答案 0 :(得分:3)

我使用伟大的ObjectListView代码项目中的一些代码找到了答案: http://www.codeproject.com/KB/list/ObjectListView.aspx

调用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;
    }

使用此数据结构:

    [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给出包含滚动句柄本身的总最大滚动值,因此实际有用的最大值是nMax - nPage,其中nPage是滚动句柄的大小。

这很棒!

答案 1 :(得分:0)

我无法直接回答您的问题,但根据您的描述,您似乎真的想要使用列表视图的虚拟模式来管理大型数据集。

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

答案 2 :(得分:0)

在有人需要的情况下,我借用了上面的代码,并且使用键盘上的下一页,下一页和结束键,拖动或单击滚动条并达到最大底部,使用了一些改进,以处理onMaximumBottomScroll事件鼠标滚轮垂直或水平旋转。这对我来说就像一种魅力。

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

完成...享受它!