Click here to Skip to main content
Licence 
First Posted 29 Oct 2003
Views 138,586
Bookmarked 42 times

ListView Column Sorter

By | 3 Nov 2003 | Article
A column sorter that sorts columns with strings and numbers, but also the first column on image and then on string.

Sample Image - ListViewColumnSorter.jpg

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;

   // Determine if clicked column is already the column that is being sorted.
   if ( e.Column == lvwColumnSorter.SortColumn )
   {
     // Reverse the current sort direction for this column.
     if (lvwColumnSorter.Order == SortOrder.Ascending)
     {
      lvwColumnSorter.Order = SortOrder.Descending;
     }
     else
     {
      lvwColumnSorter.Order = SortOrder.Ascending;
     }
   }
   else
   {
    // Set the column number that is to be sorted; default to ascending.
    lvwColumnSorter.SortColumn = e.Column;
    lvwColumnSorter.Order = SortOrder.Ascending;
   }

   // Perform the sort with these new sort options.
   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
{
 /// <summary>
 /// This class is an implementation of the 'IComparer' interface.
 /// </summary>
 public class ListViewColumnSorter : IComparer
 {
  /// <summary>
  /// Specifies the column to be sorted
  /// </summary>
  private int ColumnToSort;
  /// <summary>
  /// Specifies the order in which to sort (i.e. 'Ascending').
  /// </summary>
  private SortOrder OrderOfSort;
  /// <summary>
  /// Case insensitive comparer object
  /// </summary>  private NumberCaseInsensitiveComparer ObjectCompare;
  private ImageTextComparer FirstObjectCompare;
  /// <summary>
  /// Class constructor.  Initializes various elements
  /// </summary>
  public ListViewColumnSorter()
  {
   // Initialize the column to '0'
   ColumnToSort = 0;
   // Initialize the sort order to 'none'
   //OrderOfSort = SortOrder.None;
   OrderOfSort = SortOrder.Ascending;
   // Initialize my implementationof CaseInsensitiveComparer object
   ObjectCompare = new NumberCaseInsensitiveComparer();
   FirstObjectCompare = new ImageTextComparer();
  }  /// <summary>
  /// This method is inherited from the IComparer interface.
  /// It compares the two objects passed\
  /// using a case insensitive comparison.
  /// </summary>
  /// <param name="x">First object to be compared</param>
  /// <param name="y">Second object to be compared</param>
  /// <returns>The result of the comparison. "0" if equal,
  /// negative if 'x' is less than 'y' and positive
  /// if 'x' is greater than 'y'</returns>
  public int Compare(object x, object y)
  {
   int compareResult;
   ListViewItem listviewX, listviewY;
   // Cast the objects to be compared to ListViewItem objects
   listviewX = (ListViewItem)x;
   listviewY = (ListViewItem)y;
   if (ColumnToSort == 0)
   {
    compareResult = FirstObjectCompare.Compare(x,y);
   }
   else
   {
    // Compare the two items
    compareResult = 
      ObjectCompare.Compare(listviewX.SubItems[ColumnToSort].Text,
      listviewY.SubItems[ColumnToSort].Text);
   }
   // Calculate correct return value based on object comparison
   if (OrderOfSort == SortOrder.Ascending)
   {
    // Ascending sort is selected,
    // return normal result of compare operation
    return compareResult;
   }
   else if (OrderOfSort == SortOrder.Descending)
   {
    // Descending sort is selected,
    // return negative result of compare operation
    return (-compareResult);
   }
   else
   {
    // Return '0' to indicate they are equal
    return 0;
   }
  }
    
  /// <summary>
  /// Gets or sets the number of the column to which
  /// to apply the sorting operation (Defaults to '0').
  /// </summary>
  public int SortColumn
  {
   set
   {
    ColumnToSort = value;
   }
   get
   {
    return ColumnToSort;
   }
  }
  /// <summary>
  /// Gets or sets the order of sorting to apply
  /// (for example, 'Ascending' or 'Descending').
  /// </summary>
  public SortOrder Order
  {
   set
   {
    OrderOfSort = value;
   }
   get
   {
    return OrderOfSort;
   }
  }
    
 }
 public class ImageTextComparer : IComparer
 {
  //private CaseInsensitiveComparer ObjectCompare;
  private NumberCaseInsensitiveComparer ObjectCompare;
        
  public ImageTextComparer()
  {
   // Initialize the CaseInsensitiveComparer object
   ObjectCompare = new NumberCaseInsensitiveComparer();
  }
  public int Compare(object x, object y)
  {
   //int compareResult;
   int image1, image2;
   ListViewItem listviewX, listviewY;
   // Cast the objects to be compared to ListViewItem objects
   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)
  { 
   // in case x,y are strings and actually number,
   // convert them to int and use the base.Compare for comparison
   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)
  { // use a regular expression to find out if string is actually a number
   Regex objNotWholePattern=new Regex("[^0-9]");
   return !objNotWholePattern.IsMatch(strNumber);
  }  
 }
}

History

2003-11-04 - Have added "How to use it" to description.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Sven So.

Software Developer (Senior)
biggest furniture dealer in the world
Germany Germany

Member



Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
BugObject reference not set to an instance of an object. PinmemberInfinity8272:51 24 Aug '11  
QuestionRe: Object reference not set to an instance of an object. PinmemberSven So.2:58 24 Aug '11  
GeneralRe: Object reference not set to an instance of an object. PinmemberInfinity8272:58 24 Aug '11  
GeneralRe: Object reference not set to an instance of an object. PinmemberSven So.3:00 24 Aug '11  
Questionwhy does the compare methode occure when a new item gets added? PinmemberEmanuel Steininger9:12 7 May '11  
QuestionRe: why does the compare methode occure when a new item gets added? PinmemberSven So.22:23 9 May '11  
GeneralMy vote of 2 PinmemberCharith Jayasundara15:24 27 Apr '11  
GeneralMy vote of 3 Pinmembershelby6715:43 3 Apr '11  
GeneralIsWholeNumber fix PinmemberTwinity0:37 10 Nov '09  
AnswerRe: IsWholeNumber fix PinmemberSven So.2:14 16 Nov '09  
GeneralObjectCompare.Compare throws Exception index out of range PinmemberirafN7865:18 21 May '08  
AnswerRe: ObjectCompare.Compare throws Exception index out of range PinmemberMember 780502622:42 3 Jul '11  
GeneralWorks great for short lists Pinmemberscotlfs7:04 11 Apr '08  
GeneralRe: Works great for short lists Pinmemberstotti_no123:37 13 Apr '08  
GeneralRe: Works great for short lists - remove sorter during population PinmemberSoerenD4:51 21 Aug '08  
AnswerRe: Works great for short lists - remove sorter during population Pinmemberstotti_no17:13 25 Aug '08  
GeneralThx hero PinmemberCptkli16:14 19 Nov '07  
QuestionCannot sort empty rows? PinmemberMJay18:58 16 Oct '06  
QuestionRe: Cannot sort empty rows? Pinmemberstotti_no120:56 16 Oct '06  
AnswerRe: Cannot sort empty rows? PinmemberMJay16:57 17 Oct '06  
AnswerRe: Cannot sort empty rows? Pinmemberstotti_no120:57 17 Oct '06  
GeneralRe: Cannot sort empty rows? PinmemberMJay21:54 19 Oct '06  
QuestionDont work!? PinmemberAndy.C22:25 5 Apr '06  
AnswerRe: Dont work!? Pinmemberstotti_no122:35 5 Apr '06  
GeneralRe: Dont work!? PinmemberAndy.C23:09 5 Apr '06  

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Mobile
Web01 | 2.5.120517.1 | Last Updated 4 Nov 2003
Article Copyright 2003 by Sven So.
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid