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

发布于 2024-12-07 07:58:37 字数 1107 浏览 1 评论 0原文

我有一个 .NET 3.5 WinForm,它有一个 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();
    }
}

是,当用户按住滚动条“手柄”到位时,手柄不会移动(这意味着视图实际上并没有以编程方式向下滚动),但事实上是这样。

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

I have a .NET 3.5 WinForm that has a ListView with the View set in Details mode. It functions as a scrollable list of status items on a long background task. I have the most recent ListViewItem (status entry) added to the bottom. To assure that it is seen, I ensure the visibility of the new item after adding. This all works fine; the list view automatically scrolls to the bottom to show the most recent item.

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

The problem is if the user is scrolling up to look at older messages, the ListView will be scrolled down to make the new item visible as it comes in. Is there a way to control this behavior to check if the user is interacting with the scrollbar (specifically, if they're holding down the mouse button on the scrollbar)? It is probably also acceptable to detected if the scroll is always at the bottom. if it is not at the bottom, then I would not ensure the visibility of the latest item. Something like:

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

What's strange is that when the user is holding down the scrollbar "handle" in place, the handle doesn't move (implying that the view is not actually being scrolled down programatically), but in infact is.

Update: Is it possible to detect the position of the scrollbar, i.e., if i'ts at the bottom or not?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

二货你真萌 2024-12-14 07:58:37

解决此问题的两个步骤:

  1. WinForms ListView 没有 Scrolled 事件。我们需要定义一个。
  2. 确定 ListView 何时空闲,并仅在空闲一段时间后调用 EnsureVisible。

对于第一个问题,从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();
    }
}

Two steps to solving this problem:

  1. The WinForms ListView doesn't have a Scrolled event. We'll need to define one.
  2. Determining when the ListView is idle, and calling EnsureVisible only when it's been idle for awhile.

For the first problem, inherit a new class from ListView, override the Windows message pump, and raise an event when the user scrolls it:

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

Now we know when the user scrolls the list view. Your next problem is to determine whether the list view is idle; that is, if the user hasn't scrolled it in awhile.

There are multiple ways to do that. For this purpose, I'm just going to use a time stamp to indicate the last scroll time:

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();
    }
}
梅倚清风 2024-12-14 07:58:37

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

Compare to, say, SysInternals' ProcMon. Add a checkbox labeled "Auto scroll" so the user can turn it off.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文