Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

A sortable list view control

0.00/5 (No votes)
27 Mar 2004 1  
The SortListView control extends the existing ListView control in the .NET Compact Framework, so that it will sort items, and display the sort status in the column header.

Sample Image - Net_CF_SortListView.jpg

Introduction

I have decided to kill two birds with one stone in getting to grips both with .Net and Pocket PC development, by writing a project in C# using the .NET Compact Framework.

For this project I need a sortable list view control; no problem I thought - I'll use the one in the .Net Framework. This is when you realise that a lot of the methods and properties in the documentation do not have the magic words "Supported by the .NET Compact Framework", including the ListView.Sort method. So, I decided to roll my own, called SortListView. There may be other similar classes out there, but I treated this as a learning exercise.

As it turned out, this was quite a good choice, as it also required some interop with unmanaged code, something else I am hoping to learn more about.

How to use the SortListView class

I have tried to make using the SortListView class as simple as possible.

  1. In the form designer, drag a ListView control onto the form, and position and size it as desired. This step is useful purely to set up the Size and Location properties of the ListView control. If you prefer, you can enter these manually into the code.
  2. In the Form class constructor, create an AdrianStanley.Windows.Forms.SortListView control, and a AdrianStanley.Windows.Forms.SortColumnHeader control for each column you want in the ListView, and add them to the ListView object's Columns collection.
  3. Make sure the ListView control View property is set to System.Windows.Forms.View.Details.
  4. For each SortColumnHeader object, set its ColumnHeaderSorter property. This determines how items in the column will sort. The property should be set to an instance of a class derived from AdrianStanley.Windows.Forms.SortComparer. I have provided a number of such classes (see SortComparer.cs), for sorting strings, integers, doubles, and dates.
  5. Add items to the ListView control as normal ListViewItem objects.
  6. Build the unmanaged dll, ControlEx.dll, for your target platform, and add the dll to the main .Net project. The download includes a build of this dll for Pocket PC 2003.

That should be it. Initially items in the ListView are unsorted. When you first click on a column header, the items in that column will be sorted in ascending order, and a little upwards pointing arrow will be displayed next to the text in the column header. When you click on the column header again, the arrow changes to point downwards, and the column is sorted in descending order.

Example Project

To demonstrate how simple this is, here is a complete C# Windows project that creates a sorting ListView with three columns.

using System;
using System.Globalization;
using System.Windows.Forms;
using AdrianStanley.Windows.Forms;

namespace SortListViewDemo
{
    public class SortListViewForm : System.Windows.Forms.Form
    {
        // Declare SortListView and three SortColumnHeader objects.
        private AdrianStanley.Windows.Forms.SortListView m_sortListView;
        private AdrianStanley.Windows.Forms.SortColumnHeader m_colhdrName;
        private AdrianStanley.Windows.Forms.SortColumnHeader m_colhdrAmount;
        private AdrianStanley.Windows.Forms.SortColumnHeader m_colhdrDate;

        public SortListViewForm()
        {
            // Create SortListView and three SortColumnHeader objects.
            m_sortListView  = new AdrianStanley.Windows.Forms.SortListView();
            m_colhdrName = new AdrianStanley.Windows.Forms.SortColumnHeader();
            m_colhdrDate = new AdrianStanley.Windows.Forms.SortColumnHeader();
            m_colhdrAmount=new AdrianStanley.Windows.Forms.SortColumnHeader();
            m_sortListView.Columns.Add(m_colhdrName);
            m_sortListView.Columns.Add(m_colhdrDate);
            m_sortListView.Columns.Add(m_colhdrAmount);
            m_sortListView.Size = new System.Drawing.Size(248, 272);
            m_sortListView.View = System.Windows.Forms.View.Details;
            m_colhdrName.Text = "Name";
            m_colhdrName.Width = 100;
            m_colhdrDate.Text = "Date";
            m_colhdrDate.Width = 80;
            m_colhdrAmount.Text = "Amount";
            m_colhdrAmount.Width = 60;
            m_colhdrAmount.TextAlign = HorizontalAlignment.Right;
            Controls.Add(m_sortListView);
            Text = "SortListView Demo";

            // Assign specific comparers to each column header.
            m_colhdrName.ColumnHeaderSorter  = new ComparerString();
            m_colhdrDate.ColumnHeaderSorter  = new ComparerStringAsDateTime();
            m_colhdrAmount.ColumnHeaderSorter = new ComparerStringAsDouble();

            // Add items to ListView control.
            m_sortListView.BeginUpdate();
            AddItem("Green, David", new DateTime(2001, 12, 31), 100.23);
            AddItem("Brown, Tom", new DateTime(2000, 4, 3), 56.98);
            AddItem("Pink, Jane", new DateTime(1996, 6, 15), 653.18);
            AddItem("White, Sarah", new DateTime(2006, 8, 23), 345.22);
            AddItem("Grey, Richard", new DateTime(2003, 9, 18), 27.74);
            m_sortListView.EndUpdate();
        }

        private void AddItem(string name, DateTime date, double amount)
        {
            string[] displayInfo = new string[3];
            displayInfo[0] = name;            
            displayInfo[1] = date.ToString("d");
            NumberFormatInfo nfi = new NumberFormatInfo();
            nfi.NumberDecimalDigits = 2;
            displayInfo[2] = amount.ToString("N", nfi);                    
            m_sortListView.Items.Add(new ListViewItem(displayInfo));
        }

        protected override void Dispose( bool disposing )
        {
            m_sortListView.Dispose();
            base.Dispose( disposing );
        }

        static void Main() 
        {
            Application.Run(new SortListViewForm());
        }
    }
}

Persisting State

The SortListView class can persist state if desired. The persisted state consists of the index of the current sort column, and the sort order for each column. The persistance mechanism uses the OpenNETCF.Win32 namespace, available from http://www.opennetcf.org/. The persistance mechanism is disabled by default, as not everyone will have the OpenNETCF.Win32 namespace. To enable the persistance mechanism, define the preprocessor constant PERSIST_SORTLISTVIEW in the project settings, set the SortListView.PersistKeyName property to the key to be used in the registry for persisting values, and then call the LoadState and SaveState methods to respectively load the state from the registry, and to save the state to the registry.

I recommend that a value of the form "SOFTWARE\CompanyName\ProductName\ListViewName" is used for the SortListView.PersistKeyName property.

The Main Classes

There are three main classes involved in this project. I have used the XML comments feature of the .Net development environment to document the classes, so for detailed information I suggest you read that - preferably after generating the HTML files (Tools, Build Comment Web Pages...).

SortListView

The SortListView class represents a Windows list view control, which displays a collection of sorted items in a details view. The SortListView class extends the existing .Net Compact Framework ListView class, when it is used in a details view, with ListView.View set to View.Details. In details view, the ListView control has a column header. The SortListView class will automatically sort the items in the ListView control when a column header is clicked.

When a column header is clicked for the first time, the items in the column are sorted in ascending order. The column is now the sorted column; the ordering of items in the other columns follow the ordering of the items in the clicked column. Clicking the column header again will sort the items in the column in descending order. A sort arrow is shown in the column header to show the direction of the sort - an upwards pointing arrow for ascending order, and a downwards pointing arrow for descending order. By default the sort arrow is shown to the right of any text in the column header. If the column header text is aligned to the right then the sort arrow will be shown to the left of the text.

Each column has its own sort order, and its own comparer for determining how items in the column should be sorted. The sort order is defined as one of the values in the enum AdrianStanley.Windows.Forms.SortOrder, and the comparer is defined as an instance of a class derived from AdrianStanley.Windows.Forms.SortComparer. The AdrianStanley.Windows.Forms namespace defines some existing comparers for sorting string, int, short, long, double and DateTime objects.

The SortListView class requires unmanaged code (contained in ControlEx.dll) to show the sort arrow within the column header.

SortColumnHeader

The SortColumnHeader class sisplays a single column in a SortListView control, and represents a column header in a AdrianStanley.Windows.Forms.SortListView control.

A column header is an item in a SortListView control that contains heading text, and a sort order. SortColumnHeader objects can be added to a SortListView using the Add method of the base ListView.ColumnHeaderCollection class.

SortColumnHeader provides the Sorting property to set the sort order for the column, and the SortComparer property to set the comparer to be used to sort items in the column.

SortComparer

The SortComparer class is used in conjunction with theSortListView.Sort method, and provides a way to customize the sort order of items in a SortListView.

The class is marked as abstract, as it acts as a base class for derived classes which implement the Compare method.

Several classes derived from SortComparer are provided:

  • ComparerString. Compares alphabetic strings.
  • CompareStringAsShort. Compares shorts represented as strings.
  • CompareStringAsInt. Compares integers represented as strings.
  • CompareStringAsLong. Compares longs represented as strings.
  • CompareStringAsDouble. Compares doubles represented as strings.
  • CompareStringAsDateTime. Compares dates represented as strings.

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