I have found a solution in MSDN for ListView sorting…
But I found the code to be taking too much time to display the ListView properly when a column is clicked…
So I am asking for a solution to speed it up. I have to sort a ListView containing more than 10,000 items. Here is my whole code…
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using System.Runtime.InteropServices;
namespace ListViewSorter
{
class ListViewSorter
{
const Int32 HDF_SORTDOWN = 0x200;
const Int32 HDF_SORTUP = 0x400;
const Int32 HDI_FORMAT = 0x4;
const Int32 HDM_GETITEM = 0x120b;
const Int32 HDM_SETITEM = 0x120c;
const Int32 LVM_GETHEADER = 0x101f;
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto, EntryPoint = "SendMessage")]
static extern IntPtr SendMessageLVCOLUMN(IntPtr hWnd, UInt32 msg, IntPtr wParam, ref LVCOLUMN lParam);
[StructLayout(LayoutKind.Sequential)]
public struct LVCOLUMN
{
public Int32 mask;
public Int32 cx;
[MarshalAs(UnmanagedType.LPTStr)]
public string pszText;
public IntPtr hbm;
public Int32 cchTextMax;
public Int32 fmt;
public Int32 iSubItem;
public Int32 iImage;
public Int32 iOrder;
}
public void SetSortIcon( ListView listview, int ColumnIndex)
{
IntPtr clmHdr = SendMessage(listview.Handle, LVM_GETHEADER, IntPtr.Zero, IntPtr.Zero);
SortOrder sorting = listview.Sorting;
for (int i = 0; i < listview.Columns.Count; i++)
{
IntPtr clmPtr = new IntPtr(i);
LVCOLUMN lvColumn = new LVCOLUMN();
lvColumn.mask = HDI_FORMAT;
SendMessageLVCOLUMN(clmHdr, HDM_GETITEM, clmPtr, ref lvColumn);
if (sorting != SortOrder.None && i == ColumnIndex)
{
if (sorting == SortOrder.Ascending)
{
lvColumn.fmt &= ~HDF_SORTDOWN;
lvColumn.fmt |= HDF_SORTUP;
}
else
{
lvColumn.fmt &= ~HDF_SORTUP;
lvColumn.fmt |= HDF_SORTDOWN;
}
}
else
{
lvColumn.fmt &= ~HDF_SORTDOWN & ~HDF_SORTUP;
}
SendMessageLVCOLUMN(clmHdr, HDM_SETITEM, clmPtr, ref lvColumn);
}
}
public int SortColumn(ListView listview, int ColumnIndex, int sortColumn)
{
if (ColumnIndex != sortColumn)
{
sortColumn = ColumnIndex;
listview.Sorting = SortOrder.Ascending;
}
else
{
if (listview.Sorting == SortOrder.Ascending)
listview.Sorting = SortOrder.Descending;
else
listview.Sorting = SortOrder.Ascending;
}
SetSortIcon(listview, sortColumn);
listview.Sort();
listview.ListViewItemSorter = new ListViewItemComparer(ColumnIndex,
listview.Sorting);
return sortColumn;
}
}
class ListViewItemComparer : IComparer
{
private int col;
private SortOrder order;
public ListViewItemComparer()
{
col = 0;
order = SortOrder.Ascending;
}
public ListViewItemComparer(int column, SortOrder order)
{
col = column;
this.order = order;
}
public int Compare(object x, object y)
{
int returnVal;
try
{
System.DateTime firstDate =
DateTime.Parse(((ListViewItem)x).SubItems[col].Text);
System.DateTime secondDate =
DateTime.Parse(((ListViewItem)y).SubItems[col].Text);
returnVal = DateTime.Compare(firstDate, secondDate);
}
catch
{
returnVal = String.Compare(((ListViewItem)x).SubItems[col].Text,
((ListViewItem)y).SubItems[col].Text);
}
if (order == SortOrder.Descending)
returnVal *= -1;
return returnVal;
}
}
}
Can anyone help me out of this problem?
One of the ways that comes in my mind now is use od
data-bindingand setVirtualModehttp://msdn.microsoft.com/en-us/library/system.windows.forms.listview.virtualmode.aspx. Property totrue.Doing so you wil achieve foliwing:
your big custom data
data-layercustom management. In other words you make a sort on data and bind it tolistviewand not sortinglistviewitems.listView.VirtualMode=true;will forcelistviewcontrol to create listview items only for that items that are visible in ui. In other words, if you have 10.000 items indatacollectionbut on UI I can se only 15 of them, due the window dimension, the rendering and lustviewitem ui artifact creation time will be spend only for 15 and not for 10.000 like it does in your case.Hope this helps.