How can I display a sort arrow in the header of the sorted column in a list view which follows the native look of the operating system?
views:
2968answers:
2
                +17 
                A: 
                
                
              You can use the following extension method to set the sort arrow to a particular column:
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public static class ListViewExtensions
{
    [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
    private struct LVCOLUMN
    {
     public Int32 mask;
     public Int32 cx;
     [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPTStr)]
     public string pszText;
     public IntPtr hbm;
     public Int32 cchTextMax;
     public Int32 fmt;
     public Int32 iSubItem;
     public Int32 iImage;
     public Int32 iOrder;
    }
    private const Int32 HDI_FORMAT = 0x4;
    private const Int32 HDF_SORTUP = 0x400;
    private const Int32 HDF_SORTDOWN = 0x200;
    private const Int32 LVM_GETHEADER = 0x101f;
    private const Int32 HDM_GETITEM = 0x120b;
    private const Int32 HDM_SETITEM = 0x120c;
    [System.Runtime.InteropServices.DllImport("user32.dll")]
    private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
    [System.Runtime.InteropServices.DllImport("user32.dll", EntryPoint = "SendMessage")]
    private static extern IntPtr SendMessageLVCOLUMN(IntPtr hWnd, Int32 Msg, IntPtr wParam, ref LVCOLUMN lPLVCOLUMN);
    public static void SetSortIcon(this System.Windows.Forms.ListView ListViewControl, int ColumnIndex, System.Windows.Forms.SortOrder Order)
    {
     IntPtr ColumnHeader = SendMessage(ListViewControl.Handle, LVM_GETHEADER, IntPtr.Zero, IntPtr.Zero);
     for (int ColumnNumber = 0; ColumnNumber <= ListViewControl.Columns.Count - 1; ColumnNumber++)
     {
      IntPtr ColumnPtr = new IntPtr(ColumnNumber);
      LVCOLUMN lvColumn = new LVCOLUMN();
      lvColumn.mask = HDI_FORMAT;
      SendMessageLVCOLUMN(ColumnHeader, HDM_GETITEM, ColumnPtr, ref lvColumn);
      if (!(Order == System.Windows.Forms.SortOrder.None) && ColumnNumber == ColumnIndex)
      {
       switch (Order)
       {
        case System.Windows.Forms.SortOrder.Ascending:
         lvColumn.fmt &= ~HDF_SORTDOWN;
         lvColumn.fmt |= HDF_SORTUP;
         break;
        case System.Windows.Forms.SortOrder.Descending:
         lvColumn.fmt &= ~HDF_SORTUP;
         lvColumn.fmt |= HDF_SORTDOWN;
         break;
       }
      }
      else
      {
       lvColumn.fmt &= ~HDF_SORTDOWN & ~HDF_SORTUP;
      }
      SendMessageLVCOLUMN(ColumnHeader, HDM_SETITEM, ColumnPtr, ref lvColumn);
     }
    }
}
Then, you can call the extension method like such:
myListView.SetSortIcon(0, SortOrder.Ascending);
                  Andrew Moore
                   2008-10-31 16:38:00
                
              Note that Application.EnableVisualStyles(); must be called for the code above to work.
                  Rune
                   2008-12-01 18:26:57
                No it doesn't. It works as well for unstyled ListViews.
                  Andrew Moore
                   2009-01-02 19:55:29
                The LVCOLUMN you defined is actually HDITEM.  I realize since you define it yourself that it doesn't matter, but when translating that into C++ it confused me for a few :).
                  Bob
                   2009-10-26 18:10:37
                +1: Almost a year and a half later, and I find this. Great work, many thanks!
                  Codesleuth
                   2010-02-04 10:30:12