Brad
Brad

Reputation: 21160

how do I sort Integers in a listview

How do I sort columns of integers in a ListView

c#, .net 2.0, Winform

System.Windows.Forms.ListView

Upvotes: 7

Views: 19252

Answers (7)

YourFriend
YourFriend

Reputation: 1

Public Class Form1

Private Sub btnSortListView_Click(sender As Object, e As EventArgs) Handles btnSortListView.Click
        If btnSortListView.Text = "Sort Ascending" Then

            ListViewGar.ListViewItemSorter = New IntegerComparer(1)
            ListViewGar.Sort()

            btnSortListView.Text = "Not Sort"

        Else
            ListViewGar.ListViewItemSorter = New IntegerComparer(0)
            btnSortListView.Text = "Sort Ascending"
        End If

    End Sub
End Class

 Public Class IntegerComparer
    Implements System.Collections.IComparer

    Private _colIndex As Integer

    Public Sub New(ByVal colIndex As Integer)
        MyBase.New
        Me._colIndex = colIndex
    End Sub

    'Public Function Compare(ByVal x As Object, ByVal y As Object) As Integer
    '    Dim nx As Integer = Integer.Parse(CType(x, ListViewItem).SubItems(Me._colIndex).Text)
    '    Dim ny As Integer = Integer.Parse(CType(y, ListViewItem).SubItems(Me._colIndex).Text)
    '    Return nx.CompareTo(ny)
    'End Function

    Private Function IComparer_Compare(x As Object, y As Object) As Integer Implements IComparer.Compare
        Dim nx As Integer = Integer.Parse(CType(x, ListViewItem).SubItems(Me._colIndex).Text)
        Dim ny As Integer = Integer.Parse(CType(y,ListViewItem).SubItems(Me._colIndex).Text)

        Dim colIndPlus As Integer = Me._colIndex
        Do While nx.CompareTo(ny) = 0
            colIndPlus = colIndPlus + 1
            nx = Integer.Parse(CType(x, ListViewItem).SubItems(colIndPlus).Text)
            ny = Integer.Parse(CType(y, ListViewItem).SubItems(colIndPlus).Text)
        Loop

        Return nx.CompareTo(ny)

    End Function
End Class

image before and after sort

Upvotes: 0

Martin.Martinsson
Martin.Martinsson

Reputation: 2154

class ListViewAutoSorter : System.Collections.IComparer
{
    private int Column = 0;
    private System.Windows.Forms.SortOrder Order = SortOrder.Ascending;

    public ListViewAutoSorter(int Column, SortOrder Order)
    {
        this.Column = Column;
        this.Order = Order;
    }

    public int Compare(object x, object y) // IComparer Member
    {
        if (!(x is ListViewItem))
            return (0);
        if (!(y is ListViewItem))
            return (0);

        var l1 = (ListViewItem)x;
        var l2 = (ListViewItem)y;

        var value1 = 0.0;
        var value2 = 0.0;

        if (Double.TryParse(l1.SubItems[Column].Text, out value1) && 
            Double.TryParse(l2.SubItems[Column].Text, out value2))
        {
            if (Order == SortOrder.Ascending)
            {
                return value1.CompareTo(value2);
            }
            else
            {
                return value2.CompareTo(value1);
            }
        }
        else
        {
            var str1 = l1.SubItems[Column].Text;
            var str2 = l2.SubItems[Column].Text;

            if (Order == SortOrder.Ascending)
            {
                return str1.CompareTo(str2);
            }
            else
            {
                return str2.CompareTo(str1);
            }
        }
    }
}

Upvotes: 0

VicF
VicF

Reputation: 21

I used Neil-N's class but changed the if statement to test the Type property instead of the Tag property. I set each column to Type Number (instead of Text) that had an integer value in it. Sort works great.

if (l1.ListView.Columns[Column].Type.ToString() == "Number")

Upvotes: 0

Grammarian
Grammarian

Reputation: 6882

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.

Upvotes: 6

Neil N
Neil N

Reputation: 25258

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.

Upvotes: 22

Fredrik Mörk
Fredrik Mörk

Reputation: 158309

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();

Upvotes: 4

Jimmy Chandra
Jimmy Chandra

Reputation: 6580

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.

Upvotes: 0

Related Questions