views:

37

answers:

3

I have a ListView with VirtualMode = true and huge number of items (for now ~800,000).

My goal is to sum a field in all selected items, each time selected items changed.

The problem is that enumerating all selected items takes long time when huge number of items are selected. for example, it takes 1 second for enumerate 800,000 selected items. This means that for each single selection change, the user have to wait 1 whole second before the GUI will be responsive again, and that annoying.

I cannot understand why enumerating selected items so slow, enumerating the same number of items in a simple array takes nothing.

How can i speed up the process of enumerating selected items in ListView ?

A: 

It depends on how you're doing it, and you might want to elaborate a bit with some code, but couldn't you keep a running total as each item is selected rather than going through the whole list every time a selection is made?

Kendrick
the code is simple: foreach (int index in listView1.SelectedIndices); nothing special. the selection changed events of the listview dont tell me exactly what changes, so each time i need to reenumerate the whole selected items.
DxCK
If you aren't getting the info out of the current control, you may have to subclass it and add the tally method in there, either "on change" or accessing the underlying data. How are you accessing the data to be summed, it isn't in SelectedIndicies so the re-direction there could be what's sucking up the CPU time.
Kendrick
+1  A: 

One of the problems with the WinForms ListView is that it is build on top of the Win32Control so each request to the ListView has to pass from managed to unmanned code and back again.

var myArray = new int[myListView.SelectedIndices.Count];
myListView.SelectedIndices.CopyTo(myArray) 

may be quicker, it is worth givening it a try

Otherwise have you considered using WPF? You could write a single WPF control for the list, then host it within the WinForm form.

Ian Ringrose
Thanks, but the CopyTo() method have exactly the same performance as regular enumerating. WPF is not an option for me right now because i need to support Windows 2000.
DxCK
A: 

The underlying control is the main problem. It just takes a certain amount of time to examine each item and decide if it is the next selected row.

You can make the enumeration process about twice as fast by sending messages directly to the control:

[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int msg, int wParam, int lParam);

private void button1_Click(object sender, EventArgs e)
{
    Stopwatch sw = new Stopwatch();

    sw.Start();
    IntPtr h = this.listView1.Handle;
    int j = 0;
    int i = SendMessage(h, 0x100C, -1, 2);
    while (i > -1) {
        j++;
        i = SendMessage(h, 0x100C, i, 2);
    }

    sw.Stop();
    this.toolStripStatusLabel1.Text = String.Format("Timed: {0} items in {1}ms",
        j, sw.ElapsedMilliseconds);
}

On my machine, this halved the time needed to iterate the selected items. But that process is never going to be instant.

Grammarian