Make a ListView control sort using all of its columns in C#

You can make the ListView sort by setting its Sorting property to Ascending or Descending. However, the control only sorts on its items not their sub-items. It won't even use the sub-items to break ties when the items have the same text. This example makes it use the items and sub-items.

To modify the control's sorting behavior, you must create a class that implements the IComparer interface. (For instructions on implementing an interface, see Implement an interface in C#.) The key to this class is the Compare function, which takes as parameters two ListViewItem objects to compare and returns -1, 0, or 1 to indicate whether the first should be considered less than, equal to, or greater than the second.

The ListViewAllColumnComparer class shown in the following code compares two ListView items.

// Compares two ListView items using all of their columns.
class ListViewAllColumnComparer : System.Collections.IComparer
{
private SortOrder SortOrder;

public ListViewAllColumnComparer(SortOrder sort_order)
{
SortOrder = sort_order;
}

// Compare two ListViewItems.
public int Compare(object object_x, object object_y)
{
// Get the objects as ListViewItems.
ListViewItem item_x = object_x as ListViewItem;
ListViewItem item_y = object_y as ListViewItem;

// Loop through the sub-items.
for (int i = 0; i < item_x.SubItems.Count; i++)
{
// If item_y is out of sub-items,
// then it comes first.
if (item_y.SubItems.Count <= i) return 1;

// Get the sub-items.
string string_x = item_x.SubItems[i].Text;
string string_y = item_y.SubItems[i].Text;

// Compare them.
int result = CompareValues(string_x, string_y);

if (result != 0) return result;
}

// If we get here, we have an exact match.
return 0;
}

// Compare two items. If they look like
// numbers or dates, compare them as such.
private int CompareValues(string string_x, string string_y)
{
// Compare them.
int result;
double double_x, double_y;
if (double.TryParse(string_x, out double_x) &&
double.TryParse(string_y, out double_y))
{
// Treat as a number.
result = double_x.CompareTo(double_y);
}
else
{
DateTime date_x, date_y;
if (DateTime.TryParse(string_x, out date_x) &&
DateTime.TryParse(string_y, out date_y))
{
// Treat as a date.
result = date_x.CompareTo(date_y);
}
else
{
// Treat as a string.
result = string_x.CompareTo(string_y);
}
}

// Return the correct result depending on whether
// we're sorting ascending or descending.
if (SortOrder == SortOrder.Ascending)
{
return result;
}
else
{
return -result;
}
}
}
The class uses private variable SortOrder to keep track of its sort order. This value is set by the class's constructor.

The Compare function loops through the sub-items held by the two ListView items and uses the CompareValues method to compare them.

CompareValues tries to compare the values as doubles and dates. For example, as strings "9" comes after "100" but as numbers 9 comes before 100. Similarly as strings "10/10/2010" comes before "1/1/2009" but as dates 10/10/2010 comes after 1/1/2009.

   

 

What did you think of this article?




Trackbacks
  • No trackbacks exist for this post.
Comments
  • No comments exist for this post.
Leave a comment

Submitted comments are subject to moderation before being displayed.

 Name

 Email (will not be published)

 Website

Your comment is 0 characters limited to 3000 characters.