How do I sort columns of integers in a ListView
c#, .net 2.0, Winform
System.Windows.Forms.ListView
How do I sort columns of integers in a ListView
c#, .net 2.0, Winform
System.Windows.Forms.ListView
I'd do it in the data source (model) instead of the view. Sort it there and it should update it in the view through databinding.
This is how I accomplished being able to sort on multiple columns, and being able to sort each column as a number, or as text.
First use this class:
class Sorter : System.Collections.IComparer
{
public int Column = 0;
public System.Windows.Forms.SortOrder Order = SortOrder.Ascending;
public int Compare(object x, object y) // IComparer Member
{
if (!(x is ListViewItem))
return (0);
if (!(y is ListViewItem))
return (0);
ListViewItem l1 = (ListViewItem)x;
ListViewItem l2 = (ListViewItem)y;
if (l1.ListView.Columns[Column].Tag == null)
{
l1.ListView.Columns[Column].Tag = "Text";
}
if (l1.ListView.Columns[Column].Tag.ToString() == "Numeric")
{
float fl1 = float.Parse(l1.SubItems[Column].Text);
float fl2 = float.Parse(l2.SubItems[Column].Text);
if (Order == SortOrder.Ascending)
{
return fl1.CompareTo(fl2);
}
else
{
return fl2.CompareTo(fl1);
}
}
else
{
string str1 = l1.SubItems[Column].Text;
string str2 = l2.SubItems[Column].Text;
if (Order == SortOrder.Ascending)
{
return str1.CompareTo(str2);
}
else
{
return str2.CompareTo(str1);
}
}
}
}
In your form's constructor, set the sorter like this:
lvSeries.ListViewItemSorter = new Sorter();
Then handle the ColumnClick even of your listview control like this:
private void lvSeries_ColumnClick(object sender, ColumnClickEventArgs e)
{
Sorter s = (Sorter)lvSeries.ListViewItemSorter;
s.Column = e.Column;
if (s.Order == System.Windows.Forms.SortOrder.Ascending)
{
s.Order = System.Windows.Forms.SortOrder.Descending;
}
else
{
s.Order = System.Windows.Forms.SortOrder.Ascending;
}
lvSeries.Sort();
}
This is all dependent on the Tag property of each column either being set to "Numeric" or not, so the sorter knows how to sort.
In the above example I cast the values as floats when numeric, you may want to change that to int.
You will need to create a class that implements the IComparer
interface (the non-generic one). In that class you read the Text
property from the correct sub-item, convert it to int, and do the comparison:
public class IntegerComparer : IComparer
{
private int _colIndex;
public IntegerComparer(int colIndex)
{
_colIndex = colIndex;
}
public int Compare(object x, object y)
{
int nx = int.Parse((x as ListViewItem).SubItems[_colIndex].Text);
int ny = int.Parse((y as ListViewItem).SubItems[_colIndex].Text);
return nx.CompareTo(ny);
}
}
Then you assign such a comparer to the ListViewItemSorter property and invoke the sort method of the ListView control:
// create a comparer for column index 1 and assign it to the control, and sort
myListView.ListViewItemSorter = new IntegerComparer(1);
myListView.Sort();
If you are getting started with a ListView, your life will be much much easier if you use an ObjectListView instead. ObjectListView is an open source wrapper around .NET WinForms ListView, and it solves all these annoying little problems that normally make working with a ListView so frustrating. For example, it automatically sorts ints so that '100' comes after '3' (DateTimes, bools, and everything else sorts correctly too).
Seriously, you will never want to go back to a plain ListView after using an ObjectListView.
Yes, I am the author -- but that doesn't mean I'm biased... OK, well maybe it does :) Look here for some other people's opinions.