Sorting Items

Better ListView has extensive support for sorting, while it is usually very easy (few lines of code) to customize sorting by one's needs.

The only action needed to enable sorting is to set BetterListViewColumnHeader.Style to Sortable on every column you wish to enable user sorting.

Multi-Column Sorting

When the AllowMultiColumnSorting property is set to true and there are multiple columns with Style property set to Sortable, user can sort items by multiple columns by holding Shift key while clicking on the sortable columns.

Here is a list of movies sorted by two columns:

In this case, user first clicked on the Director column, and then twice on the Title column while holding Shift key. Now the list is sorted by the director's name in ascending order, but when director names are the same, their movie titles are sorted in descending order.

Sorted columns can also be un-sorted by clicking on them while holding a Control key.

Multi-Column Sorting from User Code

Better ListView uses list-based data structure called SortList (accessible with the property of the same name) to store current sort state. SortList contains indices and sort orders of the respective columns.

When a single solumn is sorted, SortList contains one BetterListViewSortInfo instance with index and sort order of that column.

SortList can be cloned (it is actually cloned every time you get a SortList instance through the SortList property getter). It is possible to copy sort state of one ListView to another:

C#

listView2.SortList = listView1.SortList;

Visual Basic

listView2.SortList = listView1.SortList

The list gets sorted when SortList property is set.

Sorting Item Hierarchy

Child items are sorted by default. If you want to disable hierarchical sorting, simply set BetterListViewItem.AllowSortChildItems property to false.

Another approach to more customized hierarchical sorting (e.g. when you want to sort child items with different comparer than parent items) is to use Sort method of the item collection itself (be it BetterListView.Items or BetterListViewItem.ChildItems).

Sorting by Key or Value

Sometimes, there are items with non-textual data that cannot be sorted simply by string comparison. For example, there can be progress bars or other graphic gauges on items. To sort such items (sub-items), Better ListView can gather data from two other properties:

There are three sorting methods that are possible on each column separately (see BetterListViewColumnHeader.SortMethod):

Custom and Natural (Alphanumeric) Item Comparers

Better ListView uses BetterListView.ItemComparer for item comparison. You can set this property using custom comparer of type BetterListViewItemComparer.

There are two comparers already implemented in Better ListView. These can be used publicly and extended:

The difference between the two is explained in Alphanumeric Sorting section below.

Making a Custom Item Comparer

To make a new item comparer with custom comparison rules, create a new class inheriting from BetterListViewItemComparer.

BetterListViewItemComparer implements several methods doing item comparison on various levels. These methods can be overriden to customize sorting behavior:

It is not necessary to override all the above methods, since they are already implemented in the BetterListViewItemComparer base class.

For example, if we want to create a custom comparer that compares items accroding to their check box state:

we only have to override the Compare method. If the check box state is the leading criterion for sorting, we implement the comparison and then call Compare method of the base class (to allow for multi-column sorting, further sorting according to item text etc.). Our custom "checkbox" comparer would look like this:

C#

class CheckBoxItemComparer : BetterListViewItemComparer
{
    public override int Compare(BetterListViewItem itemA, BetterListViewItem itemB)
    {
        if (itemA != null &&
            itemB != null)
        {
            int valueA = (itemA.Checked
                              ? 1
                              : 0);

            int valueB = (itemB.Checked
                              ? 1
                              : 0);

            int result = valueA.CompareTo(valueB);

            if (result != 0)
            {
                return result;
            }
        }

        return base.Compare(itemA, itemB);
    }
}

Visual Basic

Class CheckBoxItemComparer Inherits BetterListViewItemComparer

  Public Overrides Function Compare(itemA As BetterListViewItem, itemB As BetterListViewItem) As Integer
  
    If itemA IsNot Nothing AndAlso itemB IsNot Nothing Then
    
      Dim valueA As Integer = (If(itemA.Checked, 1, 0))

      Dim valueB As Integer = (If(itemB.Checked, 1, 0))

      Dim result As Integer = valueA.CompareTo(valueB)

      If result <> 0 Then
        Return result
      End If
      
    End If

    Return MyBase.Compare(itemA, itemB)
    
  End Function
  
End Class

On the contrary, if you want to make check box the least important criteria in the sorting, put the comparison in the CompareEqualItems method.

Finally, if the comparison result of the custom comparer depends on other sub-items, consider implementing the CompareSubItems method.

Highlighting the Sorted Column

There are two properties influencing column highlighting:

The column highlighting is practical in multi-column sorting, because it shows which column is the major one (the first sorted). By default, the first sorted column is highlighted in multi-column sorting.

Alphanumeric Sorting

The most popular way of sorting (left image) is comparing text values of items by their ordinal value because such comparison is straightforward to implement.

Better ListView supports also alphanumeric (or natural) ordering of items, where numbers and words are compared separately. This gives us more convenient results (right image - see how numbers are ordered by their true value).

To use alphanumeric sorting, simply write:

C#

listView.ItemComparer = new BetterListViewNaturalItemComparer();

Visual Basic

ListView.ItemComparer = New BetterListViewNaturalItemComparer()

Suspending the Automatic Sorting

When items are sorted, any change in items (e.g. item added, label edited...) causes updating the items to keep them sorted. It is convenient in some situations to suspend this mechanism. For example, when one does several changes in items and want to re-sort them in the end.

Better ListView provides SuspendSort and ResumeSort to achieve just this. These methods work in the same fashion as BeginUpdate / EndUpdate. It is possible to nest these methods using multiple calls, so ResumeSort have to be called same number of times as SuspendSort to actually resume the automatic sorting.

The ResumeSort have a boolean parameter specifying whether this call should also update item order (perform re-sorting). If you pass true to this method, item update (re-sorting) will not be executed and is done after some change is made to items.

Unsorting

Sorting affects the order of items in the list and also introduces visual cues of the sort state. These can be removed by simply calling Unsort method.

Alternatively, setting BetterListView.SortList to either empty SortList or null does the same job.

Sample Source Code

C#

this.listView.BeginUpdate();

this.listView.Columns.Add("Text");

this.listView.Columns[0].Style = BetterListViewColumnHeaderStyle.Sortable;

this.listView.Items.AddRange(
    new[]
    {
        "Beta 009",
        "Alpha 113",
        "Charlie2",
        "Alpha 96",
        "Beta 030",
        "Charlie1"
    });

// suspend sorting so that items will not be sorted by setting ItemComparer (we let user to sort them by himself by clicking the column)
this.listView.SuspendSort();

// set natural item comparer provided by Better ListView
// to reset comparer, simply set it to 'null' or new instance of 'BetterListViewItemComparer'
this.listView.ItemComparer = new BetterListViewNaturalItemComparer();

// resume sorting so that user will be able to sort items by himself
this.listView.ResumeSort(true);

this.listView.EndUpdate();

Visual Basic

ListView.BeginUpdate()

ListView.Columns.Add ("Text")

ListView.Columns (0).Style = BetterListViewColumnHeaderStyle.Sortable

ListView.Items.AddRange(
    New String() {
        "Beta 009",
        "Alpha 113",
        "Charlie2",
        "Alpha 96",
        "Beta 030",
        "Charlie1"
                 })

' suspend sorting so that items will not be sorted by setting ItemComparer (we let user to sort them by himself by clicking the column)
ListView.SuspendSort()

' set natural item comparer provided by Better ListView
' to reset comparer, simply set it to 'null' or new instance of 'BetterListViewItemComparer'
ListView.ItemComparer = New BetterListViewNaturalItemComparer()

' resume sorting so that user will be able to sort items by himself
ListView.ResumeSort (True)

ListView.EndUpdate()