Sort ListView controls by all columns or clicked columns in C#


[Sort ListView controls]

The ListView control provides features to sort its values but by default it doesn’t use them. This example shows how you can add extension methods to the control to make it sort on all columns or on clicked columns.

This example is somewhat involved so I’m going to mostly explain how the pieces fit together and let you look at the code and at other examples to see how each piece works. This example uses techniques described in the following examples:

This example adds the following useful extension methods to the ListView class:

  • AddRow – Adds a new item and subitems to define a row in the ListView.
  • SetColumnHeaders – Defines column headers and their alignments.
  • SetColumnSizes – Sets all columns to the same size.
  • SizeColumnsToFitData – Sizes all columns to fit their data.
  • SizeColumnsToFitDataAndHeaders – Sizes all columns to fit their data and headers.
  • SetSortMode – Sets the control’s sort mode to SortNone, SortOnClickedColumn, or SortOnAllColumns.

All but the last of these are relatively simple extension methods that use the techniques explained by the example Easily add column headers and items to a ListView control in C#.

The SetSortMode method lets you determine whether the ListView doesn’t sort its items, sorts by the columns you click, or sorts on all columns.

For example, suppose two rows have identical values in the first three columns but differ in the fourth. Sorting on all columns lets the control properly order the rows.

The following code shows the SetSortMode extension method.

// Prepare the ListView for column sorting.
public enum SortMode
{
    SortNone,
    SortOnClickedColumn,
    SortOnAllColumns
}
public static void SetSortMode(this ListView lvw,
    SortMode sort_mode)
{
    // Get the current sort mode.
    SortMode old_sort_mode =
        (SortMode)lvw.GetValue("ListViewSortMode",
            SortMode.SortNone);

    // If the sort mode isn't changing, do nothing.
    if (sort_mode == old_sort_mode) return;

    // See what the current sorting mode is.
    if (old_sort_mode == SortMode.SortOnClickedColumn)
    {
        // Stop sorting on clicked columns.
        ListViewSortManager SortManager =
            (ListViewSortManager)lvw.GetValue(
                "ListViewSortManager", null);
        SortManager.Disable();
        lvw.RemoveValue("ListViewSortManager");
        lvw.ListViewItemSorter = null;
    }
    else if (old_sort_mode == SortMode.SortOnAllColumns)
    {
        // Stop sorting on all columns.
        lvw.ListViewItemSorter = null;
    }

    // Start the new sort mode.
    if (sort_mode == SortMode.SortNone)
    {
        lvw.RemoveValue("ListViewSortMode");
        return;
    }

    if (sort_mode == SortMode.SortOnClickedColumn)
    {
        // Sort on clicked columns.
        lvw.SetValue("ListViewSortManager",
            new ListViewSortManager(lvw));
    }
    else if (sort_mode == SortMode.SortOnAllColumns)
    {
        // Sort on all columns.
        lvw.ListViewItemSorter =
            new ListViewAllColumnComparer(SortOrder.Ascending);
        lvw.Sort();
    }

    // Save the new sort mode.
    lvw.SetValue("ListViewSortMode", sort_mode);
}

This code starts by defining the SortMode enumeration. The method itself uses an extension property named ListViewSortMode to hold the control’s SortMode value. It starts by getting the current value of that property. If the current SortMode value is the same as the new one, the method simply returns.

Next the method removes the objects that provide the current sorting method. If the current method is SortOnClickedColumn, the code gets the extension property ListViewSortManager. That value is an object used to implement the SortOnClickedColumn strategy. It provides an event handler that catches the ListView control’s ColumnClicked event and creates an appropriate object to sort the ListView control’s data. See the code and the example Sort a ListView using the column you click in C# for details about how that kind of sorting works.

If the current sort method is SortOnAllColumns, the code sets the control’s ListViewItemSorter property to null. That object is of a class that implements the IComparer interface and that provides a Compare method for the ListView that sorts its rows by comparing all of the columns. (The ListViewSortManager also sets the control’s ListViewItemSorter property behind the scenes.) For more information on using the ListViewItemSorter property, see the example Sort a ListView control using all of its columns in C#.

If the current sort mode is SortNone, the program doesn’t need to remove the current sorting method.

Having removed the current sort mode, the method adds the new one. If the new sort mode is SortNone, the code removes the ListView control’s ListViewSortMode extension property and returns.

If the new sort mode is SortOnClickedColumn, the method creates a new ListViewSortManager and saves it in the control’s ListViewSortManager extension property. The manager’s constructor initializes the object so it is ready to sort by clicked columns. In particular it installs an event handler to catch the control’s ColumnClicked event so it can sort on the clicked column.

If the new sort mode is SortOnClickedColumn, the method creates a new ListViewAllColumnComparer, assigns it to the control’s ListViewItemSorter property, and calls the control’s Sort method to make it sort its data.

Finally the method saves the new sort mode in the ListView control’s ListViewSortMode extension property so it will know the sorting mode the next time the SetSortMode method is called.

The following code shows how the main program uses SetSortMode when you click on one of its radio buttons.

// Sort on clicked columns.
private void radSortClickedColumn_Click(object sender, EventArgs e)
{
    lvwBooks.SetSortMode(
        ListViewExtensions.SortMode.SortOnClickedColumn);
}

// Sort on all columns.
private void radSortAllColumns_Click(object sender, EventArgs e)
{
    lvwBooks.SetSortMode(
        ListViewExtensions.SortMode.SortOnAllColumns);
}

// Do not sort.
private void radNoSort_Click(object sender, EventArgs e)
{
    lvwBooks.SetSortMode(ListViewExtensions.SortMode.SortNone);
}

This code simply calls the ListView control’s SetSortMode extension method passing it the desired sort mode. The rest is automatic.

The code behind the scenes is fairly complicated. Download the example and look through the code to see additional details. Once it’s built, however, the result is quite easy to use.

All of this code is provided through extension methods and properties on the ListView control, so there’s no reason why Microsoft couldn’t have added these features directly to the control class.


Download Example   Follow me on Twitter   RSS feed   Donate




This entry was posted in controls, extension methods and tagged , , , , , , , , , , , , . Bookmark the permalink.

One Response to Sort ListView controls by all columns or clicked columns in C#

  1. Pingback: Display memory usage in C# - C# HelperC# Helper

Leave a Reply

Your email address will not be published. Required fields are marked *