ListView onScroll事件

我正在编写一个简单的C#应用​​程序,我需要在Listview上使用onScroll事件。 所以我创建了类ListviewEx女巫inheritance了原始的ListView。 我发现如何从WinAPI检测滚动消息,我修改了WndProc方法。 现在我有了这个WndProc:

protected override void WndProc(ref Message m) { base.WndProc(ref m); if (m.Msg == WM_VSCROLL) { onScroll(this, new EventArgs()); } } 

但问题是,我不知道如何检测有关滚动的信息。 这个数据应该在WParam中,但在C#中没有像C ++那样的LOWORD宏,我需要切换来检测SB_ BOTTOM,SB_ ENDSCROLL,SB_PAGEUP等参数。

有没有办法如何在C#中替换LOWORD宏?

或者其他方式如何检测有关滚动的必要参数?

您可以定义WParam常量如下:

 private const int WM_HSCROLL = 0x114; private const int WM_VSCROLL = 0x115; private const int SB_HORZ = 0; private const int SB_VERT = 1; private const int SB_LINELEFT = 0; private const int SB_LINERIGHT = 1; private const int SB_PAGELEFT = 2; private const int SB_PAGERIGHT = 3; private const int SB_THUMBPOSITION = 4; private const int SB_THUMBTRACK = 5; private const int SB_LEFT = 6; private const int SB_RIGHT = 7; private const int SB_ENDSCROLL = 8; private const int SIF_TRACKPOS = 0x10; private const int SIF_RANGE = 0x1; private const int SIF_POS = 0x4; private const int SIF_PAGE = 0x2; private const int SIF_ALL = SIF_RANGE | SIF_PAGE | SIF_POS | SIF_TRACKPOS; 

检查WParam的实际代码是这样的:

 if (m.Msg == WM_VSCROLL) { ScrollInfoStruct si = new ScrollInfoStruct(); si.fMask = SIF_ALL; si.cbSize = (uint)Marshal.SizeOf(si); GetScrollInfo(msg.HWnd, SB_VERT, ref si); if (msg.WParam.ToInt32() == SB_ENDSCROLL) { ScrollEventArgs sargs = new ScrollEventArgs(ScrollEventType.EndScroll, si.nPos); onScroll(this, sargs); } } 

pinvoke.net是一个很棒的网站,可以获取windows32 API中使用的常量值,而无需自己检查头文件。

看这个例子

谢谢你的回答。 它真的帮了我:)现在我有我想要的……

这是代码:

 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.Runtime.InteropServices; using Microsoft.Win32; using System.Reflection; namespace ControlsEx { public class ListViewEx : ListView { // Windows messages private const int WM_PAINT = 0x000F; private const int WM_HSCROLL = 0x0114; private const int WM_VSCROLL = 0x0115; private const int WM_MOUSEWHEEL = 0x020A; private const int WM_KEYDOWN = 0x0100; private const int WM_LBUTTONUP = 0x0202; // ScrollBar types private const int SB_HORZ = 0; private const int SB_VERT = 1; // 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; // ListView messages private const uint LVM_SCROLL = 0x1014; private const int LVM_FIRST = 0x1000; private const int LVM_SETGROUPINFO = (LVM_FIRST + 147); public enum ScrollBarCommands : int { SB_LINEUP = 0, SB_LINELEFT = 0, SB_LINEDOWN = 1, SB_LINERIGHT = 1, SB_PAGEUP = 2, SB_PAGELEFT = 2, SB_PAGEDOWN = 3, SB_PAGERIGHT = 3, SB_THUMBPOSITION = 4, SB_THUMBTRACK = 5, SB_TOP = 6, SB_LEFT = 6, SB_BOTTOM = 7, SB_RIGHT = 7, SB_ENDSCROLL = 8 } protected override void WndProc(ref Message m) { base.WndProc(ref m); switch(m.Msg) { case WM_VSCROLL: ScrollEventArgs sargs = new ScrollEventArgs(ScrollEventType.EndScroll, GetScrollPos(this.Handle, SB_VERT)); onScroll(this, sargs); break; case WM_MOUSEWHEEL: ScrollEventArgs sarg = new ScrollEventArgs(ScrollEventType.EndScroll, GetScrollPos(this.Handle, SB_VERT)); onScroll(this, sarg); break; case WM_KEYDOWN: switch (m.WParam.ToInt32()) { case (int)Keys.Down: onScroll(this, new ScrollEventArgs(ScrollEventType.SmallDecrement, GetScrollPos(this.Handle, SB_VERT))); break; case (int)Keys.Up: onScroll(this, new ScrollEventArgs(ScrollEventType.SmallIncrement, GetScrollPos(this.Handle, SB_VERT))); break; case (int)Keys.PageDown: onScroll(this, new ScrollEventArgs(ScrollEventType.LargeDecrement, GetScrollPos(this.Handle, SB_VERT))); break; case (int)Keys.PageUp: onScroll(this, new ScrollEventArgs(ScrollEventType.LargeIncrement, GetScrollPos(this.Handle, SB_VERT))); break; case (int)Keys.Home: onScroll(this, new ScrollEventArgs(ScrollEventType.First, GetScrollPos(this.Handle, SB_VERT))); break; case (int)Keys.End: onScroll(this, new ScrollEventArgs(ScrollEventType.Last, GetScrollPos(this.Handle, SB_VERT))); break; } break; } } public int ScrollPosition { get { return GetScrollPos(this.Handle, SB_VERT); } set { int prevPos; int scrollVal; if (ShowGroups == true) { prevPos = GetScrollPos(this.Handle, SB_VERT); scrollVal = -(prevPos - value); } else { // TODO: Add setScrollPosition if ShowGroups == false } SendMessage(this.Handle, LVM_SCROLL, (IntPtr)0, (IntPtr)scrollVal); } } public event ScrollEventHandler onScroll; [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool GetScrollInfo(IntPtr hwnd, int fnBar, ref SCROLLINFO lpsi); [DllImport("user32.dll")] public static extern int SendMessage( int hWnd, // handle to destination window uint Msg, // message long wParam, // first message parameter long lParam // second message parameter ); [DllImport("user32.dll")] static extern int SendMessage(IntPtr hWnd, int wMsg, int wParam, int lParam); [DllImport("user32.dll")] static extern int SendMessage(IntPtr hWnd, uint wMsg, IntPtr wParam, IntPtr lParam); [DllImport("user32.dll")] static extern int SetScrollPos(IntPtr hWnd, int nBar, int nPos, bool bRedraw); [DllImport("user32.dll", CharSet = CharSet.Auto)] static extern int GetScrollPos(IntPtr hWnd, int nBar); [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; } } } 

Martijn的答案会起作用,但不会抓住所有滚动。 仅当用户直接操作滚动条时才会发送WM_VSCROLL消息。 如果用户使用鼠标滚轮滚动,或使用UpArrow / DownArrow / PageUp / PageDown键,则不会发送WM_VSCROLL

您可以通过侦听LVN_BEGINSCROLL通知消息来捕获由滚动条和鼠标滚轮引起的滚动。

使用密钥时捕获滚动更难。 例如,在响应PageUp键滚动时没有发送给控件的消息。 在这种情况下可以做的最好的事情是监听KeyPress事件,然后检查事件之前和之后滚动条位置的更改。

当然,这可能是完全矫枉过正的目的。 WM_VSCROLL消息可能完全足以满足您的需求。 但是如果你想要捕获所有可能的滚动,请查看ObjectListView中的代码,该代码已经具有捕获所有这些可能性的Scroll事件。

@Klinki

谢谢你的酷贡献我觉得你忘了处理水平滚动

 Case WM_HSCROLL Dim sargs As New ScrollEventArgs(ScrollEventType.EndScroll, GetScrollPos(Me.Handle, SB_HORZ)) RaiseEvent OnScroll(Me, sargs) Exit Select