C# ListView滚动控件-如果用户不是';不滚动?

C# ListView滚动控件-如果用户不是';不滚动?,c#,.net,winforms,scrollbar,C#,.net,Winforms,Scrollbar,我有一个.NET3.5WinForm,它有一个ListView,视图设置为详细信息模式。它的功能是在一个长的后台任务中滚动状态项列表。我在底部添加了最新的ListViewItem(状态条目)。为了确保它被看到,我确保添加后新项目的可见性。这一切都很好;列表视图自动滚动到底部以显示最近的项目 private void AddListItem(DateTime timestamp, string message, int index) { var listItem = new ListVie

我有一个.NET3.5WinForm,它有一个ListView,视图设置为详细信息模式。它的功能是在一个长的后台任务中滚动状态项列表。我在底部添加了最新的ListViewItem(状态条目)。为了确保它被看到,我确保添加后新项目的可见性。这一切都很好;列表视图自动滚动到底部以显示最近的项目

private void AddListItem(DateTime timestamp, string message, int index)
{
    var listItem = new ListViewItem(timestamp.ToString());
    listItem.SubItems.Add(message);
    statusList.Items.Insert(index, listItem);
    statusList.Items[statusList.Items.Count - 1].EnsureVisible();
}
问题是,如果用户向上滚动查看较旧的消息,ListView将向下滚动,以使新项目进入时可见。有没有办法控制这种行为来检查用户是否与滚动条交互(特别是,如果他们按住滚动条上的鼠标按钮)?如果滚动始终位于底部,则也可以检测到滚动。如果它不在底部,那么我将无法确保最新项目的可见性。比如:

private void AddListItem(DateTime timestamp, string message, int index)
{
    var listItem = new ListViewItem(timestamp.ToString());
    listItem.SubItems.Add(message);
    statusList.Items.Insert(index, listItem);
    if (!statusList.IsScrollbarUserControlled)
    {
        statusList.Items[statusList.Items.Count - 1].EnsureVisible();
    }
}
奇怪的是,当用户按住滚动条“手柄”时,手柄不会移动(这意味着视图实际上不是通过编程向下滚动的),但实际上是这样的


更新:是否可以检测滚动条的位置,即,我是否在底部?

与SysInternals的ProcMon进行比较。添加一个标有“自动滚动”的复选框,以便用户可以将其关闭。

解决此问题的两个步骤:

  • WinForms ListView没有滚动事件。我们需要定义一个
  • 确定ListView何时空闲,并仅在ListView空闲一段时间后调用EnsureRevible
  • 对于第一个问题,从ListView继承一个新类,重写Windows消息泵,并在用户滚动它时引发事件:

    public class MyListView : ListView
    {
        public event EventHandler<EventArgs> Scrolled;
    
        protected override void WndProc(ref Message m)
        {
            base.WndProc(ref m);
    
            const int wm_vscroll = 0x115;
            if (m.Msg == wm_vscroll && Scrolled != null)
            {
                Scrolled(this, new EventArgs());
            }
        }
    }
    

    不知道为什么这是-1。虽然这不能回答问题,但您提供了一个非常合理的alternative@Stealth-一些马蹄铁系统性地否决了我的答案。不知道为什么,别担心。谢谢你的投票。这里的两个答案似乎都是正确的,但我最终还是同意你的建议,因为我认为它更多地满足了用户的需求,并且对它的功能没有那么惊讶。我按照你的建议使用了处理器监视器,对于用户体验来说效果很好。这对性能的影响有多大?这是您过去使用过的吗?我很好奇0x115常量从何而来。@JulienGuertault它来自Windows SDK中的Windows消息常量,位于CommCtrl.h和WinUser.h中。您可以在MSDN以及P/Invoke.NET上找到它们:好的,谢谢您的链接。我以为这是某种神奇的数字。是否有理由不使用宏,从而使代码更易于阅读?您所说的宏是什么意思?这是C。我将WM_SCROLL定义为一个常量,并使用该常量的名称。我不知道你怎么能说得更清楚。
    private DateTime lastScrollTime;
    
    ...
    
    listView.Scrolled += delegate { lastScrollTime = DateTime.Now };
    
    ...
    
    private void AddListItem(DateTime timestamp, string message, int index)
    {
        var listItem = new ListViewItem(timestamp.ToString());
        listItem.SubItems.Add(message);
        statusList.Items.Insert(index, listItem);
    
        // Scroll down only if the list view is idle.
        var idleTime = TimeSpan.FromSeconds(5);
        var isListViewIdle = DateTime.Now.Subtract(this.lastScrollTime) > idleTime;
        if (isListViewIdle)
        {
           statusList.Items[statusList.Items.Count - 1].EnsureVisible();
        }
    }