【问题标题】:How to speed up Winforms ListView item removal?如何加快 Winforms ListView 项目的删除?
【发布时间】:2012-10-01 16:05:01
【问题描述】:

我已经使用了 listView.BeginUpdate()listView.EndUpdate(),但删除 25k 中的 100 个项目时仍然需要大约 10 秒。

有什么想法和技巧可以让它更快?

编辑:

this.listView.BeginUpdate();
for (int i = this.listView.CheckedItems.Count - 1; i > -1; --i)
{
    this.listView.CheckedItems[i].Remove();
}
this.listView.EndUpdate();

【问题讨论】:

  • 你真的需要一次加载 25k 个项目吗?分页或滚动加载怎么样?
  • 显示代码,我可以在几毫秒内删除 100 个项目。刚刚检查了代码,我通过绑定来完成。
  • 用户可以来回滚动并随机看到列表部分,所以我不知道如何优化。
  • 我讨厌 WinForms 的缓慢性。结果?最终做 C++。
  • 顺便说一句,您可能想试试 ListView 的“虚拟模式”。

标签: c# .net winforms performance listview


【解决方案1】:

ListView 将为从列表中删除的每个项目触发一个事件。您可以尝试通过清除整个 ListView 来避免这种情况,然后立即添加一个新的项目列表,该列表会删除您想要删除的 100 个项目。 这只会触发少数事件。

【讨论】:

    【解决方案2】:

    您可以从这里开始优化:

    List<int> toRemove = new List<int>();
    
    foreach (ListViewItem item in this.listView.Items)
    {
        if (item.Checked) // check other remove conditions here
            toRemove.Add(item.Index);
    }
    
    /* sort indices descending, so you'll remove items with higher indices first
       and they will not be shifted when you remove items with lower indices */
    toRemove.Sort((x, y) => y.CompareTo(x));
    /* in this specific case you can simply use toRemove.Reverse(); 
       or iterate thru toRemove in reverse order
       because it is already sorted ascending.
       But you might want to force sort it descending in some other cases.
    */
    
    this.listView.BeginUpdate();
    
    foreach (int itemIndex in toRemove)
        this.listView.Items.RemoveAt(itemIndex); // use RemoveAt when possible. It's much faster with large collections
    
    this.listView.EndUpdate();
    

    【讨论】:

      【解决方案3】:

      这是因为每次从 Items 中删除元素时,ListView 都必须找到该项目 (walking the list to do so) 并刷新 CheckedItems 集合(它会再次迭代所有剩余的项目),因此复杂度为 O^2。

      最简单的方法是缓存 SelectedIndices 并使用 listItem.Items.RemoveAt():

      var selectedIndices = listView.SelectedIndices.Cast<int>().Reverse().ToList();
      listView.BeginUpdate();
      foreach (var index in selectedIndices) {
          listView.Items.RemoveAt(index);
      }
      listView.EndUpdate();
      

      如果不想使用 Cast 扩展方法,可以将第一行替换为:

      List<int> oToDelete = new List<int>(SelectedIndices.Count);
      foreach (int iX in SelectedIndices)
      {
         oToDelete.Add(iX);
      }
      oToDelete.Reverse();
      

      【讨论】:

      • 谢谢,但 listView 似乎没有 RemoveAt 方法。
      • 好的,我找到了,它在物品里面,但是演员崩溃了。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-18
      • 1970-01-01
      • 1970-01-01
      • 2020-01-06
      相关资源
      最近更新 更多