ListViewがアイテムを収集するコレクションを並べ替える必要があることに気付きました
。ListViewlistCollection=new ListView();
しかし、これはListViewがGUIコントロールとしてフォームに追加されない限り機能しないようです。そのため、アイテムの追加が非常に遅くなります。そのため、そもそもGUI-ListViewでVirtualModeを使用する必要があります。 。
誰かがこれについて行く方法を知っているか、正しい方向に私を向けますか?
ListViewがアイテムを収集するコレクションを並べ替える必要があることに気付きました
。ListViewlistCollection=new ListView();
しかし、これはListViewがGUIコントロールとしてフォームに追加されない限り機能しないようです。そのため、アイテムの追加が非常に遅くなります。そのため、そもそもGUI-ListViewでVirtualModeを使用する必要があります。 。
誰かがこれについて行く方法を知っているか、正しい方向に私を向けますか?
仮想モードを使用している場合は、基になるデータソースを並べ替える必要があります。お気づきかもしれませんが、ListViewItemSorterは仮想リストに対して何もしません。
非仮想リストビューを使用している場合は、AddRange()を使用することもできます。これは、すでに説明したBeginUpdate / EndUpdateの使用に加えて、一連のAdd()よりも大幅に高速です。
ObjectListView(.NET WinForms ListViewのオープンソースラッパー)は、すでにこれらすべての手法を使用して高速化しています。これは、通常のListViewよりも大幅に改善されています。通常モードと仮想モードの両方のリストビューをサポートし、両方をはるかに使いやすくします。たとえば、並べ替えは完全に自動的に処理されます。
基本的に、データ ポンプ自体に並べ替えを適用する必要があります。
listview sort virtualmodeをGoogleで簡単に検索しました。最初の結果は、上記の引用が取られたこのページでした。
たとえば、データソースが DataView の場合、ListView の代わりにこれに並べ替えを適用します。
アイテムを追加するときのパフォーマンスの問題である場合は、barismが示唆するようにします。VirtualMode の代わりに BeginUpdate/EndUpdate を使用してください。
try {
listView1.BeginUpdate();
// add items
}
finally {
listView1.EndUpdate();
}
既存のプロジェクトで VirtualMode True を切り替えるのと同じ問題がありましたが、解決策は驚くほど簡単でした。
最初のステップでは、ListView.Items コレクションではなく、ListViewItem のリストを作成しています。
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;
}
}
これがあなたを助けることを願っています。
非常に大きなリストの場合、仮想モードの ListView が確かな答えです。非仮想モードでは、リスト全体を描画してからビューにクリップするように見えますが、仮想モードでは、ビュー内のリストを描画するだけです。私の場合、リストは 40K+ レコードでした。非仮想モードでは、ListView の更新に数分かかる場合があります。仮想モードでは、それは瞬時でした。
リストを並べ替えるには、既に述べたように、基になるデータソースを並べ替える必要があります。それは簡単な部分です。また、表示を強制的に更新する必要がありますが、これは自動的には行われません。ListView.TopItem.Index を使用して、並べ替え前の仮想 ListView の一番上の行に対応する基になるデータ ソースのインデックスを見つけることができます。次のように、C# 関数として実装できる ListView の表示行数を返す API 呼び出しもあります。
public const Int32 LVM_GETCOUNTPERPAGE = 0x1040;
public static int GetListViewRows( ListView xoView )
{
return (int)WindowsMessage.SendMessage( xoView.Handle, LVM_GETCOUNTPERPAGE, 0, 0 );
}
これにより、更新する必要がある範囲を計算できます。残っている唯一の問題は、データがソートされた後に表示されるものと既存の表示をどのように調整するかということです。同じデータ要素を一番上の行に残したい場合は、新しくソートされたリストで新しいインデックスを見つけるメカニズムを用意する必要があるため、一番上の位置でそれを置き換えることができます - SQL IDENTITY と本質的に同等のもの.
beginupdate() と endupdate() を試しましたか? beginupdate/endupdate を使用すると、データの追加がはるかに高速になります (beginupdate を呼び出すと、endupdate を呼び出すまで listview は描画されません)。
listView1.BeginUpdate();
for (int i = 0; i < 20000; i++)
{
listView1.Items.Add("abdc", 1);
}
listView1.EndUpdate();