【问题标题】:How to sort ListView items when ListView is in VirtualMode?ListView处于VirtualMode时如何对ListView项目进行排序?
【发布时间】:2016-09-15 15:37:13
【问题描述】:

我意识到我必须对 ListView 从中收集项目的集合进行排序:
ListView listCollection = new ListView();

但这似乎不起作用,除非将 ListView 作为 GUI 控件添加到表单中,这反过来又使得添加项目非常慢,因此为什么我必须在我的 GUI-ListView 上使用 VirtualMode第一名。

有谁知道如何解决这个问题或为我指明正确的方向?

【问题讨论】:

    标签: c# listview sorting virtualmode


    【解决方案1】:

    基本上,您需要对数据泵本身应用排序。

    我在 Google 上快速搜索了listview sort virtualmode。第一个结果是this page,上面的引用来自哪里。

    例如,如果您的数据源是 DataView,则对其应用排序而不是 ListView。

    如果只是添加项目时的性能问题,我会按照barism的建议进行;使用 BeginUpdate/EndUpdate 而不是 VirtualMode。

    try {
      listView1.BeginUpdate();
      // add items
    }
    finally {
      listView1.EndUpdate();
    }
    

    【讨论】:

    • 程序仍然挂起,我必须使用 VM,因为列表可能会变得非常大(50k+ 项)
    • 好吧,在这种情况下(如果您绝对需要加载 50k+ 项),我会将这些项目存储在某种列表中,并在那里对项目进行排序(如前所述,您需要应用排序到数据泵本身),尽管您在对这么多项目进行排序时显然会遇到一些延迟,除非您找到一些我不熟悉的超级排序算法:-)(这并非完全不可想象)
    【解决方案2】:

    如果您使用虚拟模式,则必须对基础数据源进行排序。您可能已经发现,ListViewItemSorter 对虚拟列表没有任何作用。

    如果您使用的是非虚拟列表视图,您还可以使用 AddRange(),它比一系列 Add() 快得多——除了使用已经描述的 BeginUpdate/EndUpdate。

    ObjectListView(.NET WinForms ListView 的开源包装器)已经使用所有这些技术来提高自身速度。它比普通的 ListView 有了很大的改进。它同时支持普通模式和虚拟模式列表视图,并使它们更易于使用。例如,排序是完全自动处理的。

    【讨论】:

      【解决方案3】:

      我在使用现有项目切换 VirtualMode True 时遇到了同样的问题,但解决方案非常简单:

      第一步,我填充 ListViewItem 列表,而不是 ListView.Items 集合:

      private List<ListViewItem> _ListViewItems;
      

      然后我实现了 RetrieveVirtualItem 方法

      private void mLV_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
      {
          e.Item = _ListViewItems[e.ItemIndex];
      }
      

      最后,我使用之前使用的相同类对 ListViewItem 列表进行排序,我只需要更改基类

      _ListViewItems.Sort((System.Collections.Generic.IComparer<ListViewItem>)new ListViewItemComparer(new int[] { e.Column }, mLV.Sorting));
      

      这是我的 IComparer 类实现:

      class ListViewItemComparer : System.Collections.Generic.IComparer<ListViewItem>
      {
          int[] mColonne;
          private System.Windows.Forms.SortOrder order;
          public ListViewItemComparer(int[] mCols)
          {
              this.mColonne = mCols;
              this.order = System.Windows.Forms.SortOrder.Ascending;
          }
      
          public ListViewItemComparer(int[] mCols, System.Windows.Forms.SortOrder order)
          {
              this.mColonne = mCols;
              this.order = order;
          }
      
          public int Compare(ListViewItem x, ListViewItem y)
          {
              int returnVal = -1;
      
              foreach (int mColonna in mColonne)
              {
                  double mNum1;
                  double mNum2;
      
                  String mStr1 = "";
                  String mStr2 = "";
      
                  if ((x.SubItems[mColonna].Text == "NULL") && (x.SubItems[mColonna].ForeColor == Color.Red))
                  {
                      mStr1 = "-1";
                  }
                  else
                  {
                      mStr1 = x.SubItems[mColonna].Text;
                  }
      
                  if ((y.SubItems[mColonna].Text == "NULL") && (y.SubItems[mColonna].ForeColor == Color.Red))
                  {
                      mStr2 = "-1";
                  }
                  else
                  {
                      mStr2 = y.SubItems[mColonna].Text;
                  }
      
      
                  if ((double.TryParse(mStr1, out mNum1) == true) && (double.TryParse(mStr2, out mNum2) == true))
                  {
                      if (mNum1 == mNum2)
                      {
                          returnVal = 0;
                      }
                      else if (mNum1 > mNum2)
                      {
                          returnVal = 1;
                      }
                      else
                      {
                          returnVal = -1;
                      }
                  }
                  else if ((double.TryParse(mStr1, out mNum1) == true) && (double.TryParse(mStr2, out mNum2) == false))
                  {
                      returnVal = -1;
                  }
                  else if ((double.TryParse(mStr1, out mNum1) == false) && (double.TryParse(mStr2, out mNum2) == true))
                  {
                      returnVal = 1;
                  }
                  else
                  {
                      returnVal = String.Compare(mStr1, mStr2);
                  }
      
                  if (returnVal != 0)
                  {
                      break;
                  }
              }
      
              // Determine whether the sort order is descending.
              if (order == System.Windows.Forms.SortOrder.Descending)
              {
                  // Invert the value returned by String.Compare.
                  returnVal *= -1;
              }
              return returnVal;
          }
      }
      

      希望这会对你有所帮助。

      【讨论】:

      • 在虚拟模式下,不能使用 ListViewItemSorter。
      • 出色的解决方法。尝试和测试。它就像一个魅力。
      【解决方案4】:

      您尝试过 beginupdate() 和 endupdate() 吗?使用 beginupdate/endupdate 时添加数据的速度要快得多。(当您调用 beginupdate 时,listview 在调用 endupdate 之前不会绘制)

      listView1.BeginUpdate();
      for (int i = 0; i < 20000; i++)
      {
      listView1.Items.Add("abdc", 1);
      }
      listView1.EndUpdate();
      

      【讨论】:

      • 添加 maaany 项目时,应用程序仍然挂起。
      • 您可以创建一个线程来添加项目。(或在每个 Items.Add() 之后调用 processmessages() 但线程比 processmessages 好得多)
      【解决方案5】:

      对于非常大的列表,虚拟模式 ListView 是肯定的答案。在非虚拟模式下,它似乎绘制整个列表,然后将其剪辑到视图中,而在虚拟模式下,它只是在视图中绘制列表。在我的情况下,列表是 40K+ 记录。在非虚拟模式下,更新 ListView 可能需要几分钟时间。在虚拟模式下,它是瞬时的。

      如前所述,要对列表进行排序,您必须对底层数据源进行排序。那是容易的部分。您还需要强制刷新显示,这不会自动完成。您可以使用 ListView.TopItem.Index 在底层数据源中查找与排序前的 Virtual ListView 的顶行相对应的索引。还有一个 API 调用可以返回 ListView 中的显示行数,您可以将其实现为 C# 函数,如下所示:

      public const Int32 LVM_GETCOUNTPERPAGE = 0x1040;
      
      public static int GetListViewRows( ListView xoView ) 
      {
         return (int)WindowsMessage.SendMessage( xoView.Handle, LVM_GETCOUNTPERPAGE, 0, 0 );
      }
      

      这将让您计算必须更新的范围。剩下的唯一问题是如何将现有显示与数据排序后显示的内容相协调。如果你想在第一行保留相同的数据元素,你必须有一些机制可以在新排序的列表中找到它的新索引,这样你就可以在顶部位置替换它 - 这基本上等同于 SQL IDENTITY .

      【讨论】:

        猜你喜欢
        • 2020-01-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-03-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多