ListView滚动控件 - 如果用户不滚动,则滚动到底部?

时间:2011-09-30 16:58:17

标签: c# .net winforms scrollbar

我有一个.NET 3.5 WinForm,它有一个ListView,在View模式下设置了View。它在长时间背景任务中充当状态项的可滚动列表。我将最新的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();
    }
}

奇怪的是,当用户按住滚动条“句柄”时,句柄不会移动(暗示视图实际上没有以编程方式向下滚动),但实际上是。

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

2 个答案:

答案 0 :(得分:4)

解决此问题的两个步骤:

  1. WinForms ListView没有滚动事件。我们需要定义一个。
  2. 确定ListView何时处于空闲状态,并仅在空闲一段时间后调用EnsureVisible。
  3. 对于第一个问题,从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());
            }
        }
    }
    

    现在我们知道用户何时滚动列表视图。您的下一个问题是确定列表视图是否空闲;也就是说,如果用户暂时没有滚动它。

    有多种方法可以做到这一点。为此,我将使用时间戳来指示上次滚动时间:

    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();
        }
    }
    

答案 1 :(得分:2)

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