删除最旧的项目时防止 ListView 垂直滚动

Posted

技术标签:

【中文标题】删除最旧的项目时防止 ListView 垂直滚动【英文标题】:Prevent ListView vertically scrolling when oldest item is removed 【发布时间】:2014-03-26 11:22:39 【问题描述】:

我正在使用 Windows 窗体 ListView 控件来显示项目列表,总共最多 1000 个项目,但在列表视图中一次只能看到大约 20 个项目(列表视图使用详细信息视图)。

我经常将新项目添加到列表视图的底部,并自动滚动到新添加的项目(使用item.EnsureVisible()),以便用户可以看到最新数据。当列表大小超过 1000 项时,我会从列表中删除最旧的列表项(即索引 0,列表视图顶部的项)以使其保持在 1000 项。

现在是我的问题:

每当列表视图中的选择发生变化时,与该项目相关的其他详细信息会显示在表单的其他位置。发生此选择的更改时,我停止自动滚动到新项,以便用户的所选项目保持它的位置(即,列表在其选择中的项目时不会滚动到最新项),只需重新- 当用户关闭表单的其他详细信息部分时,启用自动滚动到最新的。

这一切都很好,除了当我从列表视图中删除最旧的项目时(以确保列表不会超过 1000 个项目):当我删除最旧的项目时,列表视图会滚动所有内容自动增加 1(即我没有以编程方式完成此滚动)。我意识到,如果所选项目是最早的 20 个事件之一(这使得最早的 20 个事件成为可见事件),它将别无选择,只能在删除最早的事件时滚动可见项目,但如果选择是,比如说,在列表的中途,它应该不需要滚动列表视图项。

当我删除最旧的项目时,有什么办法可以防止列表视图自动向上滚动一个?或者我是否必须通过确保可见项目保持在我移除最旧项目之前的位置来解决它(这似乎很麻烦)?

【问题讨论】:

在删除项目后,根据您的要求将 SelectedIndex 强制为您想要的。 不确定您的意思 - 这并不意味着所选项目仍然可见? 【参考方案1】:

好的,这是我在 C# 中的不理想(但至少大部分工作)解决方案(从 VB.NET 转换,因此 *** 的语法高亮显示可以正确显示,因此对任何拼写错误表示歉意!)。

任何更好的解决方案,请提出建议!

// loop through every item in the list from the top, until we find one that is
// within the listview's visible area
private int GetListViewTopVisibleItem()

    foreach (ListViewItem item In ListView1.Items)
    
        if (ListView1.ClientRectangle.IntersectsWith(item.GetBounds(ItemBoundsPortion.Entire)))
        
            // +2 as the above intersection doesn't take into account the height
            // of the listview's header (in Detail mode, which my listview is)
            return (item.Index + 2);
        
    
    // failsafe: return a valid index (which won't be used)
    return 0;


private void RemoveOldestItem()

    // pause redrawing of the listview while we fiddle...
    ListView1.SuspendLayout();

    // if we are not auto-scrolling to the most recent item, and there are
    // still items in the list:
    int TopItemIndex = 0;
    if (!AllowAutoScroll && (ListView1.SelectedItems.Count > 0))
        TopItemIndex = GetListViewTopVisibleItem();

    // remove the first item in the list
    ListView1.Items.RemoveAt(0);

    // if we are not auto-scrolling, and the previous top visible item was not
    // the one we just removed, make that previously top-visible item visible
    // again.  (We decrement TopItemIndex as we just removed the first item from
    // the list, which means all indexes have shifted down by 1)
    if (!AllowAutoScroll && (--TopItemIndex > 0))
        ListView1.Items(TopItemIndex).EnsureVisible();

    // allow redraw of the listview now
    ListView1.ResumeLayout()

(当然,这假定所选项目是当前可见,否则这样做没有多大意义;它总是中可见不过,我的情况是,除非 selected 事件是从列表顶部删除的事件(在这种情况下,不再选择任何内容,因此问题消失了))

【讨论】:

以上是关于删除最旧的项目时防止 ListView 垂直滚动的主要内容,如果未能解决你的问题,请参考以下文章

在 WPF ListView 中,如何防止自动滚动?

SplitContainer 中的 Top ListView 不会添加垂直滚动条

如何从字典中删除最旧的元素?

git stash drop 最旧的存储(比如最旧的 5 个存储)

Android Sqlite 根据日期列删除最旧的重复结果

Flutter 如何使用 ListView 水平和 GridView 垂直滚动屏幕