CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 6 of 6
  1. #1
    Join Date
    May 2015
    Posts
    19

    [RESOLVED] ListView Sorting-Alternative

    hi

    Visual C++ is not correctly sorting entrys inside a listview.
    I have numbers such as 1, 3, 5, 10, 20, 100, 101 but they are not sortet the correct way.

    I become 1, 10, 100, 101, 3, 5, 20
    How can I fix this problem?

    thank you

  2. #2
    Join Date
    Jun 2010
    Location
    Germany
    Posts
    2,675

    Re: ListView Sorting-Alternative

    Obviously, your list view is sorting the items lexically (IOW alphabetically) rather than numerically what you actually seem to intend. The straightforward approach to fix this is assigning an object implementing the IComparer interface to the ListView::ListViewItemSorter property, which implements the sort order you want.

    Here's an implementation of a numeric sort order, sorting by item text (AKA sub-item 0):

    Code:
    // LVIC.h
    
    #pragma once
    
    using namespace System;
    using namespace System::Collections;
    using namespace System::Windows::Forms;
    
    public ref class ListViewItemComparer abstract : public IComparer
    {
    protected:
      ListViewItemComparer(IComparer ^valuecomparer) : m_valuecomparer(valuecomparer), m_nReversalFactor(1)
      {}
    
      ListViewItemComparer(IComparer ^valuecomparer, bool bReverse) :
        m_valuecomparer(valuecomparer), m_nReversalFactor(bReverse ? -1 : 1)
      {}
    
    public:
      virtual int Compare(Object ^x, Object ^y)
      {
        return m_valuecomparer->Compare(GetItemValue(safe_cast<ListViewItem ^>(x)), GetItemValue(safe_cast<ListViewItem ^>(y)))
          * m_nReversalFactor;
      }
    
    protected:
      virtual Object ^GetItemValue(ListViewItem ^lvi) abstract;
    
    protected:
      initonly IComparer ^m_valuecomparer;
    
    private:
      initonly int m_nReversalFactor;
    };
    
    public ref class NumericListViewItemComparer : public ListViewItemComparer
    {
    public:
      NumericListViewItemComparer() : ListViewItemComparer(Generic::Comparer<int>::Default)
      {}
    
    protected:
      virtual Object ^GetItemValue(ListViewItem ^lvi) override
      {
        int nNumericValue;
        int::TryParse(lvi->Text, nNumericValue);
        return nNumericValue;
      }
    };
    Though not actually strictly required here, the implementation is split into two parts: The abstract base class ListViewItemComparer, which implements the generalized list view item comparer framework that is to be specialized to the specific needs of the concrete scenario, and this specialization is what the derived class NumericListViewItemComparer does by overriding the abstract base class function GetItemValue() and passing the appropriate IComparer implementation for the type you want to base the comparison on (here: System::Collections::Generic::IComparer<int>::Default) to the base class constructor.

    You'd then just pass an instance of your item comparer class into the list view so that it applies the desired sort order, like this:

    Code:
    listView1->ListViewItemSorter = gcnew NumericListViewItemComparer;
    Seen isolated, this design looks more complicated than needed, but it can be rather easily adapted to almost any scenario that way.

    The base class has been taken practically unmodified out of one of my real-life projects an thus should be correct. The derived class, however, has been written "free hand" and is untested, so it may contain typos and other minor bugs.

    A quite flexible and powerful way of handling sorting and other aspects of a list view, that I didn't use here since it wasn't required (and also I couldn't apply it since I don't know details of your project) is to assign the object, that the list view item was created from, to the list view item's Tag property. That way any code dealing with the list view item easily gets access to the original object (needs to be cast back from Object ^ to its original concrete type), simplifying not only sorting, but also other related tasks.
    Last edited by Eri523; June 19th, 2015 at 03:45 AM.
    I was thrown out of college for cheating on the metaphysics exam; I looked into the soul of the boy sitting next to me.

    This is a snakeskin jacket! And for me it's a symbol of my individuality, and my belief... in personal freedom.

  3. #3
    Join Date
    May 2015
    Posts
    19

    Re: ListView Sorting-Alternative

    hello Eri523

    thank you very much. it is working perfect.
    how can I change from ascending to descending?

  4. #4
    Join Date
    Jun 2010
    Location
    Germany
    Posts
    2,675

    Re: ListView Sorting-Alternative

    Call the two-parameter base class constructor from the derived class and pass true for bReverse:

    Code:
    public ref class DescendingNumericListViewItemComparer : public ListViewItemComparer
    {
    public:
      NumericListViewItemComparer() : ListViewItemComparer(Generic::Comparer<int>::Default, true)
      {}
    
    protected:
      virtual Object ^GetItemValue(ListViewItem ^lvi) override
      {
        int nNumericValue;
        int::TryParse(lvi->Text, nNumericValue);
        return nNumericValue;
      }
    };
    I was thrown out of college for cheating on the metaphysics exam; I looked into the soul of the boy sitting next to me.

    This is a snakeskin jacket! And for me it's a symbol of my individuality, and my belief... in personal freedom.

  5. #5
    Join Date
    May 2015
    Posts
    19

    Re: ListView Sorting-Alternative

    Thank you very much.
    You solved my problem. It works great.

  6. #6
    Join Date
    Jun 2010
    Location
    Germany
    Posts
    2,675

    Re: ListView Sorting-Alternative

    You're welcome!

    In this case it's good practice to mark the thread [RESOLVED] using the thread tools menu at the top.

    While revisiting the topic I found a small enhancement that can be made: int, like many others of the .NET framework types, implements the IComparable interface. For types that do that, the non-generic default comparer can be used. So, adding these two protected constructors to the base class:

    Code:
      ListViewItemComparer() : m_valuecomparer(Comparer::Default), m_nReversalFactor(1)
      {}
    
      ListViewItemComparer(bool bReverse) : m_valuecomparer(Comparer::Default), m_nReversalFactor(bReverse ? -1 : 1)
      {}
    allows simplifications to derived classes in cases where the default comparer can be used.

    That way, the ascending comparer class from post #2 wouldn't need any more explicitly coded constructor at all, as the base class now is default-constructable. The descending comparer class would just need to pass a single true as the parameter to the base class constructor.
    I was thrown out of college for cheating on the metaphysics exam; I looked into the soul of the boy sitting next to me.

    This is a snakeskin jacket! And for me it's a symbol of my individuality, and my belief... in personal freedom.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured