RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Add Flexible Sort Capabilities to ListView Controls : Page 2

Learn how to make the ListView control sort by a column when a user clicks on a column header, sort by all columns, or sort in just about any other way you can imagine.

Using the SelectedColumnSorter Class
The SortableListView control can now use the SelectedColumnSorter class to sort its items by a particular column. The code fragment in Listing 1 shows key pieces of the SortableListView control. For simplicity, I've omitted the code that's not related to sorting by a selected column.

After importing the System.ComponentModel namespace, the code in Listing 1 includes a ToolboxBitmap attribute and the Class statement that indicates the control inherits from ListView:

   <ToolboxBitmap(GetType(SortableListView), _
       "tbxSortableListView")> _
   Public Class SortableListView
The control defines the SortStyles enumeration so you can indicate whether the control should sort using the default method, by all columns, or by a selected column:

   Public Enum SortStyles
   End Enum
It also declares the variable m_SelectedColumn to hold the index of the column on which it should be sorting.

The SortStyle property gets and sets a SortStyles value. The Get procedure simply returns the value saved in variable m_SortStyle:

   Public Property SortStyle() As SortStyles
         Return m_SortStyle
      End Get
The Set procedure shown in Listing 1 performs a little more work. First it checks whether the control is currently sorting by a selected column. If it is, then the code removes the sort indicator arrow by setting the column's ImageKey property to Nothing so the column doesn't display any image:

      Set(ByVal value As SortStyles)
         ' If the current style is SortSelectedColumn,
         ' remove the column sort indicator.
         If m_SortStyle = SortStyles.SortSelectedColumn Then
            If m_SelectedColumn >= 0 Then
               Me.Columns(m_SelectedColumn).ImageKey = Nothing
               m_SelectedColumn = -1
            End If
         End If
Next, the Set procedure saves the new sort style and then uses a Select Case statement to take appropriate action. When the new sort style is SortDefault, the code sets the ListViewItemSorter property to Nothing so the ListView's default sorting behavior takes over. When the sort style is SortAllColumns, the code sets the ListViewItemSorter property to a new AllColumnSorter object (described in the next section). When the new style is SortSelectedColumn, then the code sets the ListViewItemSorter property to a new SelectedColumnSorter object:

         ' Save the new value.
         m_SortStyle = value
         Select Case m_SortStyle
         Case SortStyles.SortDefault
            Me.ListViewItemSorter = Nothing
         Case SortStyles.SortAllColumns
            Me.ListViewItemSorter = New AllColumnSorter()
         Case SortStyles.SortSelectedColumn
            Me.ListViewItemSorter = _
                New SelectedColumnSorter()
         End Select
         ' Resort.
         ' Me.Sort()
      End Set
   End Property
At this point, the Set procedure could call the control's Sort method to resort the items using the new sorter. I found that confusing in the example program so I commented out the code and let the main program call the control's Sort method explicitly.

The last piece of the control's code needed for column sorting is the OnColumnClick method, called whenever the user clicks on a column header. The code starts by calling the base class's OnColumnClick method. It then determines whether the current sorting style is SortSelectedColumn:

   Protected Overrides Sub OnColumnClick( _
      ByVal e As System.Windows.Forms.ColumnClickEventArgs)
      If Me.SortStyle = SortStyles.SortSelectedColumn Then
         ' If this is the same sort column, switch the sort order.
         If e.Column = m_SelectedColumn Then
            If Me.Sorting = SortOrder.Ascending Then
               Me.Sorting = SortOrder.Descending
               Me.Sorting = SortOrder.Ascending
            End If
         End If
         ' Remove the image from the previous sort column.
         If m_SelectedColumn >= 0 Then
            Me.Columns(m_SelectedColumn).ImageKey = Nothing
         End If
         ' If we're not currently sorting, sort ascending.
         If Me.Sorting = SortOrder.None Then
            Me.Sorting = SortOrder.Ascending
         End If
         ' Save the new sort column and give it an image.
         m_SelectedColumn = e.Column
         If Me.Sorting = SortOrder.Descending Then
            Me.Columns(m_SelectedColumn).ImageKey = _
            Me.Columns(m_SelectedColumn).ImageKey = _
         End If
         ' Resort.
      End If
   End Sub
When a user clicks the same column that was selected previously, the OnColumnClick code shown switches the control's sort order, and clears the sort indicator arrow. If there's no current sort-order selection, the code uses the default ascending order.

The code then saves the newly clicked column as the selected column and sets the appropriate sort order indicator arrow for the column.

Author's Note: Your main program should set the control's SmallImageList property to an ImageList control that contains these images. Their names in the ImageList should be sortDescending.bmp and sortAscending.bmp. I've found that 16 x 14 pixel images seem to look the best.

Finally, the OnColumnClick code calls the control's Sort method to resort the items based on the newly selected column and sort order.

Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date