How to: Sort ListView Items

The .NET Compact Framework does not support the Sort method for a ListView, but you can still sort items using the IComparer interface and use the Sort method on an ArrayList.

The following table defines three classes.

Class

Description

ColHeader

Derived from the ColumnHeader class, this class is used for adding columns to the ListView control and for sorting the clicked column. It includes the ascending property to specify the direction of the sort: true specifies ascending and false specifies descending.

SortWrapper

When a column is clicked, an instance of this class is created for each ListItem and added to an ArrayList. Each wrapped item includes a property containing the index of the clicked column.

This class contains the SortComparer class.

SortComparer

Within the SortWrapper class, this class defines an implementation of the IComparer interface whose Compare method compares objects, two at a time, as the ArrayList is sorted.

The event handler for the ColumnClick event performs the sort operation as follows:

  1. Creates an instance of the ColHeader class for determining which column is clicked.

  2. Sets the ascending property of the ColHeader object to sort in the opposite direction.

  3. Gets the number of items in the list.

  4. Disables drawing the display during the sort with the BeginUpdate method.

  5. Adds a SortWrapper for each ListView item to an ArrayList.

  6. Sorts the elements in the ArrayList using a new instance of the SortComparer class whose implementation of the IComparer interface contains the logic of the sort in its Compare method.

  7. Clears the ListView control of items and repopulates the control with the sorted items from the ArrayList.

  8. Enables drawing the display with the EndUpdate method.

Note that the Sort method on an ArrayList performs an unstable sort; that is, if two elements are equal, their order might not be preserved. In contrast, a stable sort preserves the order of elements that are equal.

To create the application

  1. Create a new .NET Compact Framework project and add a ListView control.

  2. Add the SortWrapper class to your project, which also contains the SortComparer class.

    ' An instance of the SortWrapper class is created for  
    ' each item and added to the ArrayList for sorting. 
    Public Class SortWrapper
        Friend sortItem As ListViewItem
        Friend sortColumn As Integer 
    
        ' A SortWrapper requires the item and the index of the clicked column. 
        Public Sub New(ByVal Item As ListViewItem, ByVal iColumn As Integer)
            sortItem = Item
            sortColumn = iColumn
        End Sub 
    
        ' Text property for getting the text of an item. 
        Public ReadOnly Property [Text]() As String 
            Get 
                Return sortItem.SubItems(sortColumn).Text
            End Get 
        End Property 
    
        ' Implementation of the IComparer  
        ' interface for sorting ArrayList items. 
        Public Class SortComparer
            Implements IComparer
            Private ascending As Boolean 
    
    
            ' Constructor requires the sort order; 
            ' true if ascending, otherwise descending. 
            Public Sub New(ByVal asc As Boolean)
                Me.ascending = asc
            End Sub 
    
    
            ' Implemnentation of the IComparer:Compare  
            ' method for comparing two objects. 
            Public Function [Compare](ByVal x As Object, ByVal y As Object) As Integer Implements IComparer.Compare
                Dim xItem As SortWrapper = CType(x, SortWrapper)
                Dim yItem As SortWrapper = CType(y, SortWrapper)
    
                Dim xText As String = xItem.sortItem.SubItems(xItem.sortColumn).Text
                Dim yText As String = yItem.sortItem.SubItems(yItem.sortColumn).Text
                Return xText.CompareTo(yText) * IIf(Me.ascending, 1, -1)
            End Function 
        End Class 
    End Class
    
    // An instance of the SortWrapper class is created for 
    // each item and added to the ArrayList for sorting. 
    public class SortWrapper
    {
        internal ListViewItem sortItem;
        internal int sortColumn;
    
    
        // A SortWrapper requires the item and the index of the clicked column. 
        public SortWrapper (ListViewItem Item, int iColumn)
        {
            sortItem = Item;
            sortColumn = iColumn;
        }
    
        // Text property for getting the text of an item. 
        public string Text
        {
            get
            {
                return sortItem.SubItems[sortColumn].Text;
            }
        }
    
        // Implementation of the IComparer 
        // interface for sorting ArrayList items. 
        public class SortComparer : IComparer
        {
            bool ascending;
    
            // Constructor requires the sort order; 
            // true if ascending, otherwise descending. 
            public SortComparer(bool asc)
            {
                this.ascending = asc;
            }
    
            // Implemnentation of the IComparer:Compare 
            // method for comparing two objects. 
            public int Compare(object x, object y)
            {
                SortWrapper xItem = (SortWrapper) x;
                SortWrapper yItem = (SortWrapper) y;
    
                string xText = xItem.sortItem.SubItems[xItem.sortColumn].Text;
                string yText = yItem.sortItem.SubItems[yItem.sortColumn].Text;
                return xText.CompareTo(yText) * (this.ascending ? 1 : -1);
            }
        }
    }
    
  3. Add the ColHeader class to your project.

    ' The ColHeader class is a ColumnHeader object with an  
    ' added property for determining an ascending or descending sort. 
    ' True specifies an ascending order, false specifies a descending order. 
    Public Class ColHeader
        Inherits ColumnHeader
        Public ascending As Boolean 
    
        Public Sub New(ByVal [text] As String, ByVal width As Integer, ByVal align As HorizontalAlignment, ByVal asc As Boolean)
            Me.Text = [text]
            Me.Width = width
            Me.TextAlign = align
            Me.ascending = asc
        End Sub 
    End Class
    
    // The ColHeader class is a ColumnHeader object with an 
    // added property for determining an ascending or descending sort. 
    // True specifies an ascending order, false specifies a descending order. 
    public class ColHeader : ColumnHeader
    {
        public bool ascending;
        public ColHeader(string text, int width,  HorizontalAlignment align, bool asc)
        {
            this.Text = text;
            this.Width = width;
            this.TextAlign = align;
            this.ascending = asc;
        }
    }
    
  4. Add columns with the ColHeader class, and add ListView items.

    ' Set to Details view. 
    Me.listView1.View = View.Details
    
    ' Add columns using the ColHeader class. The fourth     
    ' parameter specifies true for an ascending sort order.
    listView1.Columns.Add(New ColHeader("Name", 110, HorizontalAlignment.Left, True))
    listView1.Columns.Add(New ColHeader("Region", 50, HorizontalAlignment.Left, True))
    listView1.Columns.Add(New ColHeader("Sales", 70, HorizontalAlignment.Left, True))
    
    ' Add the data.
    listView1.Items.Add(New ListViewItem(New String() {"Archer, Karen", "4", "0521.28"}))
    listView1.Items.Add(New ListViewItem(New String() {"Benson, Max", "8", "0828.54"}))
    listView1.Items.Add(New ListViewItem(New String() {"Bezio, Marin", "3", "0535.22"}))
    listView1.Items.Add(New ListViewItem(New String() {"Higa, Sidney", "2", "0987.50"}))
    listView1.Items.Add(New ListViewItem(New String() {"Martin, Linda", "6", "1122.12"}))
    listView1.Items.Add(New ListViewItem(New String() {"Nash, Mike", "7", "1030.11"}))
    listView1.Items.Add(New ListViewItem(New String() {"Sanchez, Ken", "1", "0958.78"}))
    listView1.Items.Add(New ListViewItem(New String() {"Smith, Ben", "5", "0763.25"}))
    
    ' Connect the ListView.ColumnClick event to the ColumnClick event handler. 
    AddHandler Me.listView1.ColumnClick, AddressOf listView1_ColumnClick
    
    this.listView1.View = View.Details;
    
    // Add columns using the ColHeader class. The fourth 
    // parameter specifies true for an ascending sort order.
    listView1.Columns.Add(new ColHeader("Name", 110, HorizontalAlignment.Left, true));
    listView1.Columns.Add(new ColHeader("Region", 50, HorizontalAlignment.Left, true));
    listView1.Columns.Add(new ColHeader("Sales", 70, HorizontalAlignment.Left, true));
    
    // Add the data.
    listView1.Items.Add(new ListViewItem(new string[] {"Archer, Karen","4","0521.28"}));
    listView1.Items.Add(new ListViewItem(new string[] {"Benson, Max","8","0828.54"}));
    listView1.Items.Add(new ListViewItem(new string[] {"Bezio, Marin","3","0535.22"}));
    listView1.Items.Add(new ListViewItem(new string[] {"Higa, Sidney","2","0987.50"}));
    listView1.Items.Add(new ListViewItem(new string[] {"Martin, Linda","6","1122.12"}));
    listView1.Items.Add(new ListViewItem(new string[] {"Nash, Mike","7","1030.11"}));
    listView1.Items.Add(new ListViewItem(new string[] {"Sanchez, Ken","1","0958.78"}));
    listView1.Items.Add(new ListViewItem(new string[] {"Smith, Ben","5","0763.25"}));
    
    // Connect the ListView.ColumnClick event to the ColumnClick event handler. 
    this.listView1.ColumnClick += new ColumnClickEventHandler(listView1_ColumnClick);
    
  5. Add code to perform the sort.

    Private Sub listView1_ColumnClick(ByVal sender As Object, ByVal e As ColumnClickEventArgs)
    
        ' Create an instance of the ColHeader class.  
        Dim clickedCol As ColHeader = CType(Me.listView1.Columns(e.Column), ColHeader)
    
        ' Set the ascending property to sort in the opposite order.
        clickedCol.ascending = Not clickedCol.ascending
    
        ' Get the number of items in the list. 
        Dim numItems As Integer = Me.listView1.Items.Count
    
        ' Turn off display while data is repoplulated. 
        Me.listView1.BeginUpdate()
    
        ' Populate an ArrayList with a SortWrapper of each list item. 
        Dim SortArray As New ArrayList
        Dim i As Integer 
        For i = 0 To numItems - 1
            SortArray.Add(New SortWrapper(Me.listView1.Items(i), e.Column))
        Next i
    
        ' Sort the elements in the ArrayList using a new instance of the SortComparer 
        ' class. The parameters are the starting index, the length of the range to sort, 
        ' and the IComparer implementation to use for comparing elements. Note that 
        ' the IComparer implementation (SortComparer) requires the sort   
        ' direction for its constructor; true if ascending, othwise false.
        SortArray.Sort(0, SortArray.Count, New SortWrapper.SortComparer(clickedCol.ascending))
    
        ' Clear the list, and repopulate with the sorted items. 
        Me.listView1.Items.Clear()
        Dim z As Integer 
        For z = 0 To numItems - 1
            Me.listView1.Items.Add(CType(SortArray(z), SortWrapper).sortItem)
        Next z
        ' Turn display back on. 
        Me.listView1.EndUpdate()
    End Sub
    
    private void listView1_ColumnClick(object sender, ColumnClickEventArgs e)
    {
    
        // Create an instance of the ColHeader class.
        ColHeader clickedCol = (ColHeader)this.listView1.Columns[e.Column];
    
        // Set the ascending property to sort in the opposite order.
        clickedCol.ascending = !clickedCol.ascending;
    
        // Get the number of items in the list. 
        int numItems = this.listView1.Items.Count;
    
        // Turn off display while data is repoplulated. 
        this.listView1.BeginUpdate();
    
        // Populate an ArrayList with a SortWrapper of each list item.
        ArrayList SortArray = new ArrayList();
        for (int i = 0; i < numItems; i++)
        {
            SortArray.Add(new SortWrapper(this.listView1.Items[i], e.Column));
        }
    
        // Sort the elements in the ArrayList using a new instance of the SortComparer 
        // class. The parameters are the starting index, the length of the range to sort, 
        // and the IComparer implementation to use for comparing elements. Note that 
        // the IComparer implementation (SortComparer) requires the sort 
        // direction for its constructor; true if ascending, othwise false.
        SortArray.Sort(0, SortArray.Count, new SortWrapper.SortComparer(clickedCol.ascending));
    
        // Clear the list, and repopulate with the sorted items. 
        this.listView1.Items.Clear();
        for  (int i = 0; i < numItems; i++)
            this.listView1.Items.Add(((SortWrapper)SortArray[i]).sortItem);
    
        // Turn display back on. 
        this.listView1.EndUpdate();
    }
    

Compiling the Code

This example requires references to the following namespaces:

See Also

Concepts

Custom Control Development

.NET Compact Framework How-to Topics

Other Resources

Windows Forms Controls in the .NET Compact Framework