# Sorting Items

Better ListView: Ultimate .NET ListView replacement control for WinForms (C#, VB.NET)
Download More Info

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:

- BetterListViewItem.Key (BetterListViewSubItem.Key)

  - .IComparable object explicitly specified by the user for item comparison purposes.

- BetterListViewItem.Value (BetterListViewSubItem.Value)

  - Value of a property from bound data source specified by the ValueMember property of the corresponding column (see Data Binding for more information).

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

- Auto

  - Key is used primarily for comparison; if not available the comparer falls back to Value, and if even this is not available, Text is used.

- Text

  - Text is always used for comparison.

- Key

  - Key is used always for comparison.

## 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:

- BetterListViewDefaultItemComparer

- BetterListViewNaturalItemComparer

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:

- Compare

  - Compares two items. This is the core method for item comparison. BetterListViewItemComparer implements multi-column sorting here and calls CompareSubItems and CompareEqualItems from here.

- CompareSubItems

  - Compares two sub-items in the same column. Here the BetterListViewItemComparer implements sorting methods (specified by BetterListViewColumnHeader.SortMethod property) and calls CompareValues from here. The sub-items are compared here either by value, key or by text.

- CompareValues

  - Compares two arbitrary IComparable values in the specified order. BetterListViewItemComparer implements comparison with possible null values and regarding the sort order.

- CompareEqualItems

  - When two items are considered equal in the Compare method, BetterListViewItemComparer calls this method, which compares the items by their index.

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:

- SortedColumnsRowsHighlight

  - Affects sorted column highlighting.

- ColorSortedColumn

  - Affects color of the highlighted column.

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()

Better ListView: Ultimate .NET ListView replacement control for WinForms (C#, VB.NET)
Download More Info