【发布时间】:2009-12-05 08:51:22
【问题描述】:
我有一个使用后台工作程序生成缩略图的列表视图。当滚动列表视图时,我想暂停后台工作程序并获取滚动区域的当前值,当用户停止滚动列表视图时,根据滚动区域的值从项目开始恢复后台工作程序。
是否可以处理列表视图的滚动事件?如果是的话怎么办?如果不是,那么根据我上面的描述有什么好的选择?
【问题讨论】:
标签: c# listview event-handling scroll
我有一个使用后台工作程序生成缩略图的列表视图。当滚动列表视图时,我想暂停后台工作程序并获取滚动区域的当前值,当用户停止滚动列表视图时,根据滚动区域的值从项目开始恢复后台工作程序。
是否可以处理列表视图的滚动事件?如果是的话怎么办?如果不是,那么根据我上面的描述有什么好的选择?
【问题讨论】:
标签: c# listview event-handling scroll
您必须添加对 ListView 类的支持,以便您可以收到有关滚动事件的通知。向您的项目添加一个新类并粘贴下面的代码。编译。将新的 listview 控件从工具箱顶部拖放到表单上。为新的 Scroll 事件实现一个处理程序。
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));
}
}
}
注意滚动位置 (ScrollEventArgs.NewValue) 没有意义,它取决于 ListView 中的项目数。我将其强制为 0。按照您的要求,您希望查看 ScrollEventType.EndScroll 通知以了解用户何时停止滚动。其他任何东西都可以帮助您检测到用户开始滚动。例如:
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;
}
【讨论】:
根据@Adriaan Stander 发布的关于引发滚动事件的课程的帖子如下。
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());
}
}
}
}
像这样使用它...
声明一个字段:
private ControlScrollListener _processListViewScrollListener;
用你需要知道的滚动控件来实例化它:
_processListViewScrollListener = new ControlScrollListener(ProcessesListView);
在处理程序中连接:
_processListViewScrollListener.ControlScrolled += ProcessListViewScrollListener_ControlScrolled;
处理事件:
void ProcessListViewScrollListener_ControlScrolled(object sender, EventArgs e)
{
// do what you need to do
}
可以调整引发事件中的事件参数以包含更多有用的信息。我只需要知道我的控件已被滚动!
【讨论】:
private const uint WM_MOUSEWHEEL = 0x020A;。
看到这个帖子ListView Scroll Event
使用原生窗口类监听 对于滚动消息 列表框。可与任何控件一起使用。
【讨论】:
现在在 .net 4 中很容易捕获滚动事件。
从您的 ListView (m_ListView) 中捕获 Loaded 事件并执行以下操作:
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;
}
然后,实现您的 ScrollViewer_ScrollChanged 函数:
private void ScrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e)
{
...
}
【讨论】: