0

I can quickly clear the selection of a ListView using its SelectedIndices.Clear method, but if I want to select all the items, I have to do this:

for (int i = 0; i < lv.SelectedIndices.Count; i++)
{
    if (!lv.SelectedIndices.Contains(i))
        lv.SelectedIndices.Add(i);
}

and to invert the selection,

for (int i = 0; i < lv.SelectedIndices.Count; i++)
{
    if (lv.SelectedIndices.Contains(i))
        lv.SelectedIndices.Add(i);
    else
        lv.SelectedIndices.Remove(i);
}

Is there a quicker way?

Simon
  • 25,468
  • 44
  • 152
  • 266
  • it's a bad idea to accept them too quickly, as Grammarian's excellent late entry shows. – Simon Feb 25 '10 at 12:37

3 Answers3

2

Use the ListViewItem.Selected property:

foreach(ListViewItem item in lv.Items)
    item.Selected = true;


foreach(ListViewItem item in lv.Items)
    item.Selected = !item.Selected;

EDIT: This won't work in virtual mode.

SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
  • 1
    it's more concise, but is it quicker? Does it work in virtual mode? – Simon Feb 25 '10 at 10:57
  • @Simon: Yes, it will work in virtual mode. In virtual mode, it will be slower, but without virtual mode, it will have the same performance. – SLaks Feb 25 '10 at 14:07
1

To quickly select all the items in a ListView, have look at the long answer to this question. The method outlined there is virtually instantaneous, even for lists of 100,000 objects AND it works on virtual lists.

ObjectListView provides many helpful shortcuts like that.

However, there is no way to automatically invert the selection. SLaks method will work for normal ListViews, but not for virtual lists since you can't enumerate the Items collection on virtual lists.

On a virtual list, the best you can do is something like you first suggested::

static public InvertSelection(ListView lv) {
    // Build a hashset of the currently selected indicies
    int[] selectedArray = new int[lv.SelectedIndices.Count];
    lv.SelectedIndices.CopyTo(selectedArray, 0);
    HashSet<int> selected = new HashSet<int>();
    selected.AddRange(selectedArray);

    // Reselect everything that wasn't selected before
    lv.SelectedIndices.Clear();
    for (int i=0; i<lv.VirtualListSize; i++) {
        if (!selected.Contains(i))
            lv.SelectedIndices.Add(i);
    }
}

HashSet is .Net 3.5. If you don't have that, use a Dictionary to give fast lookups.

Be aware, this will still not be lightning fast for large virtual lists. Every lv.SelectedIndices.Add(i) call will still trigger a RetrieveItem event.

Community
  • 1
  • 1
Grammarian
  • 6,774
  • 1
  • 18
  • 32
  • Brilliant - the long answer is exactly what I was after. For inverting, I'll probably either clear then add, or select all and remove, depending on whether 50% of the rows are selected. – Simon Feb 25 '10 at 12:39
  • 1
    Actually, you can use the `Items` collection in Virtual Mode. However, it will create the ListViewItem in the indexer, so you should avoid it where possible. (I checked the source) – SLaks Feb 25 '10 at 14:09
  • @SLaks You can use `Items`, but you *cannot* enumerate it. If you try, it will throw an exception. – Grammarian Feb 26 '10 at 04:09
0

You can just set the Selected property of the ListViewItem class.

Giorgi
  • 30,270
  • 13
  • 89
  • 125