2

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

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

任何人都知道如何解决这个问题或指出我正确的方向吗?

4

5 回答 5

3

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

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

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

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

try {
  listView1.BeginUpdate();
  // add items
}
finally {
  listView1.EndUpdate();
}
于 2009-09-02T09:57:39.423 回答
3

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

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

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

于 2009-09-02T11:46:00.673 回答
2

我在现有项目中切换 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;
    }
}

希望这会帮助你。

于 2016-09-15T07:37:13.570 回答
1

您是否尝试过 beginupdate() 和 endupdate()?当您使用 beginupdate/endupdate 时添加数据要快得多。(当您调用 beginupdate 时,listview 直到您调用 endupdate 才会绘制)

listView1.BeginUpdate();
for (int i = 0; i < 20000; i++)
{
listView1.Items.Add("abdc", 1);
}
listView1.EndUpdate();
于 2009-09-02T09:55:28.353 回答
1

对于非常大的列表,虚拟模式 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 .

于 2012-05-15T15:03:02.127 回答