Problem:
I am using a ListView control in a .NET Windows Forms application. How can I programatically sort the data in the ListView by a specific column when that columns header is clicked by the user?
Resolution:
*-----------------------------------------------------------------------------------*
* TESTLISTSORT *
* *
* This example program demonstrates how to sort the rows in a Windows Forms ListView*
* control by a specific column when that columns header has been clicked. If the *
* ListView has not been sorted previously then ascending will be used as the sort *
* sequence otherwise each time a header has been clicked it will be sorted in the *
* opposite sequence in which it was previously sorted. *
* *
* This works by setting the ListViewItemSorter property of the ListView to an in- *
* stance of a class which implements the ICompare Interface, in this case, ListView *
* ColumnSorter. *
*-----------------------------------------------------------------------------------*
inherits type System.Windows.Forms.Form.
working-storage section.
01 lvwColumnSorter type testlistsort.ListViewColumnSorter.
method-id NEW.
procedure division.
invoke self::InitializeComponent
*> Create an instance of a ListView column sorter and assign it
*> to the ListView control.
set lvwColumnSorter to new testlistsort.ListViewColumnSorter
set listView1::ListViewItemSorter to lvwColumnSorter
goback.
end method.
method-id Form1_Load final private.
01 row type ListViewItem.
procedure division using by value sender as object e as type System.EventArgs.
*> Populate the ListView control with data
set row to new ListViewItem("John Smith")
invoke row::SubItems::Add("ABC Software")
invoke row::SubItems::Add("800-555-1234")
invoke listView1::Items::Add(row)
set row to new ListViewItem("Ann Johnson")
invoke row::SubItems::Add("Z-Systems Data")
invoke row::SubItems::Add("111-222-3333")
invoke listView1::Items::Add(row)
set row to new ListViewItem("Zachary Jones")
invoke row::SubItems::Add("New Life Systems")
invoke row::SubItems::Add("555-987-1111")
invoke listView1::Items::Add(row)
*> sets first row in listview to be selected row as indexes are 0 based.
set listView1::Items[0]::Selected to true
goback
end method.
method-id listView1_ColumnClick final private.
procedure division using by value sender as object e as type System.Windows.Forms.ColumnClickEventArgs.
*> 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 = type SortOrder::Ascending
set lvwColumnSorter::Order to type SortOrder::Descending
else
set lvwColumnSorter::Order to type SortOrder::Ascending
end-if
else
*> Set the column number that is to be sorted; default to ascending.
set lvwColumnSorter::SortColumn to e::Column
set lvwColumnSorter::Order to type SortOrder::Ascending
end-if
*> Perform the sort with these new sort options.
invoke listView1::Sort
goback
end method.
method-id button1_Click final private.
procedure division using by value sender as object e as type System.EventArgs.
invoke self::Close
end method.
end class.
ListViewColumnSorter class:
*>
*> This class is an implementation of the 'IComparer' interface.
*>
$set ilusing"System.Collections"
$set ilusing"System.Windows.Forms"
class-id testlistsort.ListViewColumnSorter implements type IComparer.
working-storage section.
01 ColumnToSort binary-long.
01 OrderOfSort type SortOrder.
01 ObjectCompare type CaseInsensitiveComparer.
property-id SortColumn binary-long.
getter.
set property-value to ColumnToSort
setter.
set ColumnToSort to property-value
end property.
property-id Order type SortOrder.
getter.
set property-value to OrderOfSort
setter.
set OrderOfSort to property-value
end property.
method-id New.
local-storage section.
procedure division.
*> Initialize the column to '0'
set ColumnToSort to 0
*> Initialize the sort order to 'none'
set OrderOfSort to type SortOrder::None
*> Initialize the CaseInsensitiveComparer object
set ObjectCompare to new CaseInsensitiveComparer
goback.
end method.
*> Automatically inserted Methods from System.Collections.IComparer
*> This method is inherited from the IComparer interface.
*> It compares the two objects passed using a case insensitive comparison.
method-id Compare.
01 compareResult binary-long.
01 listViewX type ListViewItem.
01 listViewY type ListViewItem.
procedure division using by value #x as object #y as object returning return-item as binary-long.
*> Cast the objects to be compared to ListViewItem objects
set listViewX to #x as type ListViewItem
set listviewY to #y as type ListViewItem
*> Compare the two items
set compareResult to ObjectCompare::Compare(listviewX::SubItems[ColumnToSort]::Text, listviewY::SubItems[ColumnToSort]::Text)
*> Calculate correct return value based on object comparison
if OrderOfSort = type SortOrder::Ascending
*> Ascending sort is selected, return normal result of compare operation
set return-item to compareResult
else
if OrderOfSort = type SortOrder::Descending
*> Descending sort is selected, return negative result of compare operation
compute return-item = compareResult * -1
else
*> Return '0' to indicate they are equal
set return-item to 0
end-if
end-if
goback
end method.
end class.