
Introduction
Long time ago I started using the ListView. After a while, I was in a desperate need of a column sorter. I just wanted to sort on each column. A while later, I thought maybe it would be good to sort on the images as well. Of course in this case it should sort on image and then on text in the first column. Yesterday I had the problem, that one column contained numbers in string form. Which of course again brought me to the next version, which should find out, if the string is actually a number and then sort on numbers. I have created an example project that utilizes all this for you. Have a look.
How to use it
If you just want to use it, it's so simple. Just download the source zip from the link on the top of the page. In your forms class, just declare this:
private ListViewColumnSorter lvwColumnSorter;
Then within the constructor of your form, you simply add:
private void MyForm()
{
lvwColumnSorter = new ListViewColumnSorter();
this.listView1.ListViewItemSorter = lvwColumnSorter;
}
Of course, now you want to be able to sort, when you click on the column title. Now in Visual Studio, you select your ListView and go to properties, select events and double-click on ColumnClick. What will be created is this:
this.listView1.ColumnClick +=
new System.Windows.Forms.ColumnClickEventHandler(this.listView1_ColumnClick);
Which means, we will need another method that will steer the sorting for us:
private void listView1_ColumnClick(object sender,
System.Windows.Forms.ColumnClickEventArgs e)
{
ListView myListView = (ListView)sender;
if ( e.Column == lvwColumnSorter.SortColumn )
{
if (lvwColumnSorter.Order == SortOrder.Ascending)
{
lvwColumnSorter.Order = SortOrder.Descending;
}
else
{
lvwColumnSorter.Order = SortOrder.Ascending;
}
}
else
{
lvwColumnSorter.SortColumn = e.Column;
lvwColumnSorter.Order = SortOrder.Ascending;
}
myListView.Sort();
}
Now you are done...
Code basics
To create a sorter for ListViews, you have to create a new class that implements the IComparer interface.
using System;
using System.Collections;
using System.Text.RegularExpressions;
using System.Windows.Forms;
namespace ColumnSorter
{
public class ListViewColumnSorter : IComparer
{
private int ColumnToSort;
private SortOrder OrderOfSort;
private ImageTextComparer FirstObjectCompare;
public ListViewColumnSorter()
{
ColumnToSort = 0;
OrderOfSort = SortOrder.Ascending;
ObjectCompare = new NumberCaseInsensitiveComparer();
FirstObjectCompare = new ImageTextComparer();
} public int Compare(object x, object y)
{
int compareResult;
ListViewItem listviewX, listviewY;
listviewX = (ListViewItem)x;
listviewY = (ListViewItem)y;
if (ColumnToSort == 0)
{
compareResult = FirstObjectCompare.Compare(x,y);
}
else
{
compareResult =
ObjectCompare.Compare(listviewX.SubItems[ColumnToSort].Text,
listviewY.SubItems[ColumnToSort].Text);
}
if (OrderOfSort == SortOrder.Ascending)
{
return compareResult;
}
else if (OrderOfSort == SortOrder.Descending)
{
return (-compareResult);
}
else
{
return 0;
}
}
public int SortColumn
{
set
{
ColumnToSort = value;
}
get
{
return ColumnToSort;
}
}
public SortOrder Order
{
set
{
OrderOfSort = value;
}
get
{
return OrderOfSort;
}
}
}
public class ImageTextComparer : IComparer
{
private NumberCaseInsensitiveComparer ObjectCompare;
public ImageTextComparer()
{
ObjectCompare = new NumberCaseInsensitiveComparer();
}
public int Compare(object x, object y)
{
int image1, image2;
ListViewItem listviewX, listviewY;
listviewX = (ListViewItem)x;
image1 = listviewX.ImageIndex;
listviewY = (ListViewItem)y;
image2 = listviewY.ImageIndex;
if (image1 < image2)
{
return -1;
}
else if (image1 == image2)
{
return ObjectCompare.Compare(listviewX.Text,listviewY.Text);
}
else
{
return 1;
}
}
}
public class NumberCaseInsensitiveComparer : CaseInsensitiveComparer
{
public NumberCaseInsensitiveComparer ()
{
}
public new int Compare(object x, object y)
{
if ((x is System.String) && IsWholeNumber((string)x)
&& (y is System.String) && IsWholeNumber((string)y))
{
return base.Compare(System.Convert.ToInt32(x),
System.Convert.ToInt32(y));
}
else
{
return base.Compare(x,y);
}
}
private bool IsWholeNumber(string strNumber)
{ Regex objNotWholePattern=new Regex("[^0-9]");
return !objNotWholePattern.IsMatch(strNumber);
}
}
}
History
2003-11-04 - Have added "How to use it" to description.