How to sort a ListView control by a column in Visual C++ .NET or in Visual C++ 2005 (816183)



The information in this article applies to:

  • Microsoft Visual C++ .NET (2003)
  • Microsoft .NET Framework 1.1
  • Microsoft Visual C++ 2005 Express Edition


For a Microsoft Visual Basic .NET version of this article, see 319399.
For a Microsoft Visual C# .NET version of this article, see 319401.

This article refers to the following Microsoft .NET Framework Class Library namespace:
  • System.Collections

IN THIS TASK

SUMMARY

This step-by-step article describes how to sort a ListView control by a column in your Microsoft Visual C++ .NET or Microsoft Visual C++ 2005 application.

When you are working with the ListView control, you may want to sort its contents based on specific column data. An example of this kind of functionality occurs in a Microsoft Windows Explorer program when you view the contents of a folder on your hard disk. In Details view, Windows Explorer displays information about the files in that folder. For example, you see the file name, the file size, the file type, and the date that the file was modified. When you click one of the column headers, the list is sorted in ascending order based on that column data. When you click the same column header again, the column is sorted in descending order.

The example in this article defines a class that inherits from the IComparer interface. Additionally, this example uses the Compare method of the CaseInsenstiveComparer class to perform the actual comparison of the items. Note that this method of comparison is not case sensitive ("Apple" is considered to be the same as "apple"). Also, note that the columns of the ListView control in this example are sorted in a "text" manner. If you want to sort in a different manner (such as numerically), you can replace the following line of code with whichever approach to sorting that you want to use:
ObjectCompare->Compare(listviewX->SubItems->Item[ColumnToSort]->Text,listviewY->SubItems->Item[ColumnToSort]->Text);
back to the top

Requirements

This article assumes that you are familiar with the following topics:
  • An intermediate understanding of Visual C++ programming concepts

The following list outlines the recommended hardware, software, network infrastructure, and service packs that you need:
  • Microsoft Visual C++ .NET 2003 or Microsoft Visual C++ 2005
back to the top

Build the sample project

Create a new project

  1. Start Microsoft Visual Studio .NET 2003 or Microsoft Visual Studio 2005.
  2. On the File menu, point to New, and then click Project. The New Project dialog box appears.
  3. Under Project Types, click Visual C++ Projects. Under Templates, click Windows Forms Application (.NET).

    Note In Visual Studio 2005, click Visual C++ under Project Types, and then click Windows Forms Application under Templates.
  4. In the Name box, type Q816183.
  5. In the Locate box, type C:\, and then click OK.

    By default, Form1 is created.
back to the top

Add and then configure a ListView control

  1. Add a ListView control to Form1. Size the form to be several inches wide and several inches tall.
  2. Right-click Form1, and then click View Code.
  3. Paste the following code in the Form1 class:
    private: ListViewColumnSorter *lvwColumnSorter;
  4. Paste the following code in the constructor function of the Form1 class, after the call to the InitializeComponent method:
    // Create an instance of a ListView column sorter and assign it 
    // to the ListView control.
    lvwColumnSorter = new ListViewColumnSorter();
    listView1->ListViewItemSorter = lvwColumnSorter;
  5. Press SHIFT+F7 to switch to the Form Designer.
  6. Double-click Form1 to create the Form1_Load event.
  7. Paste the following code in the Load event of the form:
    ColumnHeader *columnheader;		// This is used for creating column headers.
    ListViewItem *listviewitem;		// This is used to create ListView items.
    listView1->Enabled = true;
    
    // Make sure that the view is set to show details.
    listView1->set_View(System::Windows::Forms::View::Details);
    
    
    // Create some ListView items that include first and last names.
    listviewitem = new ListViewItem("John");
    listviewitem->SubItems->Add("Smith");
    this->listView1->Items->Add(listviewitem);
    
    listviewitem = new ListViewItem("Brian");
    listviewitem->SubItems->Add("Lloyd");
    this->listView1->Items->Add(listviewitem);
    
    listviewitem = new ListViewItem("Kimberly");
    listviewitem->SubItems->Add("Zimmerman");
    this->listView1->Items->Add(listviewitem);
    
    listviewitem = new ListViewItem("Tamara");
    listviewitem->SubItems->Add("Johnson");
    this->listView1->Items->Add(listviewitem);
    						
    // Create some column headers for the data. 
    columnheader = new ColumnHeader();
    columnheader->Text = "First Name";
    this->listView1->Columns->Add(columnheader);
    
    columnheader = new ColumnHeader();
    columnheader->Text = "Last Name";
    this->listView1->Columns->Add(columnheader);
    
    // Loop through and size each column header to fit the column header text.
    IEnumerator* iEnum = this->listView1->Columns->GetEnumerator();
    while(iEnum->MoveNext())				
    {
    
    	ColumnHeader *ch;
    	ch = __try_cast<ColumnHeader*>(iEnum->Current);
    	ch->set_Width(-2);
    }
    Note You must add the common language runtime support compiler option (/clr:oldSyntax) in Visual C++ 2005 to successfully compile this code sample. To do this, follow these steps:
    1. Click Project, and then click ProjectName Properties.

      Note ProjectName represents the name of the project.
    2. Expand Configuration Properties, and then click General.
    3. Click to select Common Language Runtime Support, Old Syntax (/clr:oldSyntax) in the Common Language Runtime support project setting on the right pane, click Apply, and then click OK.
    For more information about the common language runtime support compiler options, visit the following Microsoft Web site:

    /clr (Common Language Runtime Compilation)
    http://msdn2.microsoft.com/en-us/library/k8d11d4s.aspx

  8. Press SHIFT+F7 to switch to the Form Designer.
  9. Right-click the ListView control, and then click Properties.
  10. In the Properties window, click Events, and then double-click the ColumnClick event in the list of events.
  11. Paste the following code in the ColumnClick event for the ListView control:
    // Determine if the 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 == SortOrder::Ascending)
    	{
    		lvwColumnSorter->Order = SortOrder::Descending;
    	}
    	else
    	{
    		lvwColumnSorter->Order = SortOrder::Ascending;
    	}
    }
    else
    {
    	// Set the column number that is to be sorted. By default, this is in ascending order.
    	lvwColumnSorter->SortColumn = e->Column;
    	lvwColumnSorter->Order = SortOrder::Ascending;
    }
    
    // Perform the sort with these new sort options.
    listView1->Sort();
back to the top

Add and then configure the ListViewColumnSorter class

  1. On the Project menu, click Add Class to add a new class to the project.
  2. In the Add Class dialog box, click Generic C++ Class under Templates, and then click Open.

    Note In Visual Studio 2005, click Visual C++ under Templates, and then click Add.
  3. In the Generic C++ Class Wizard, type ListViewColumnSorter in the Class name box.
  4. Type IComparer in the Base Class box, and then click Finish.

    The ListViewColumnSorter class appears as follows:
    #pragma once
    
    class ListViewColumnSorter :
    	public IComparer
    {
    public:
    	ListViewColumnSorter(void);
    	~ListViewColumnSorter(void);
    };
  5. To make the ListViewColumnSorter class a Managed C++ class, add the __gc keyword in front of the ListViewColumnSorter class:
    __gc class ListViewColumnSorter :
    	public IComparer
    {
    public:
    	ListViewColumnSorter(void);
    	~ListViewColumnSorter(void);
    };
  6. Replace the code in the ListViewColumnSorter.h file with the following:
    #pragma once
    
    using namespace System;
    using namespace System::Collections;	
    using namespace System::Windows::Forms;
    
    __gc class ListViewColumnSorter: public IComparer
    {
    	// Specifies the column that is to be sorted.
    	private:
    		int ColumnToSort;
    		
    		// Specifies the order in which to sort ('Ascending' or 'Descending').
    		SortOrder OrderOfSort;
    		
    		// Case insensitive comparer object.
    		CaseInsensitiveComparer *ObjectCompare;
    
    	public:
    		ListViewColumnSorter(void);
    		~ListViewColumnSorter(void);
    		int Compare(Object *x, Object *y);
    
    		// Gets or sets the number of the column to which to apply the sorting 
      // operation (by default, this number is 0).
    	public: 
    		__property void set_SortColumn(int val)
    		{
    			ColumnToSort = (val);
    		}
    		__property int get_SortColumn()
    		{
    			return ColumnToSort;
    		}
    
    		// Gets or sets the order of sorting to apply (for example, 'Ascending' or 'Descending').
    		__property void set_Order(SortOrder val)
    		{
    			OrderOfSort = (val);
    		}
    	
    		__property SortOrder get_Order()
    		{
    			return OrderOfSort;
    		}
    };
  7. Locate the ListViewColumnSorter constructor in the ListViewColumnSorter.cpp file, and then add the following code:
    // Initialize the column to '0'.
    ColumnToSort = 0;
    
    // Initialize the sort order to 'none'.
    OrderOfSort = SortOrder::None;
    
    // Initialize the CaseInsensitiveComparer object.
    ObjectCompare = new CaseInsensitiveComparer();
  8. Implement the code for Compare method. To do this, paste the following code in the ListViewColumnSorter.cpp file:
    /// <summary>
    /// This method is inherited from the IComparer interface.  It compares the two objects
    /// that are passed by using a case insensitive comparison.
    /// </summary>
    /// <param name="x">First object to be compared</param>
    /// <param name="y">Second object to be compared</param>
    /// <returns>The result of the comparison. "0" if equal, negative if 'x' is less than 'y' and positive if 'x' is greater than 'y'</returns>
    ListViewColumnSorter::Compare(Object *x, Object *y)
    {
    	int compareResult;
    	ListViewItem *listviewX, *listviewY;
    
    	// Cast the objects to be compared to ListViewItem objects.
    	listviewX = static_cast <ListViewItem *> (x);
    	listviewY = static_cast <ListViewItem *> (y);
    
    	// Compare the two items.
    	compareResult = ObjectCompare->Compare(listviewX->SubItems->Item[ColumnToSort]->Text,listviewY->SubItems->Item[ColumnToSort]->Text);
    		
    	// Calculate correct return value based on object comparison.
    	if (OrderOfSort == SortOrder::Ascending)
    	{
    		// If ascending sort is selected, return the normal result of the compare operation.
    		return compareResult;
    	}
    	else if (OrderOfSort == SortOrder::Descending)
    	{
    		// If descending sort is selected, return the negative result of the compare operation.
    		return (-compareResult);
    	}
    	else
    	{
    		// Return '0' to indicate that they are equal.
    		return 0;
    	}
    }
  9. In the Form1.h file, add the following code on the top:
    #include "listviewcolumnsorter.h"
back to the top

Save, build, and then run the project

  1. Press CTRL+SHIFT+S to save the project.
  2. Press CTRL+SHIFT+B to build the solution.
  3. Press CTRL+F5 to run the sample project.
  4. Click the various column headers in the ListView control. When you click the header, the contents of the ListView control are sorted in ascending order based on the column that you click. When you click the same column header again, that column is sorted in descending order.
back to the top

Modification Type:MajorLast Reviewed:1/9/2006
Keywords:kbWindowsForms kbcode kbListView kbCtrl kbHOWTOmaster KB816183 kbAudDeveloper