2008-10-31 14 views

Odpowiedz

63

można wykorzystywać następujące metody rozszerzenie ustawić strzałkę sortowania do konkretnej kolumny:

[EditorBrowsable(EditorBrowsableState.Never)] 
public static class ListViewExtensions 
{ 
    [StructLayout(LayoutKind.Sequential)] 
    public struct HDITEM 
    { 
     public Mask mask; 
     public int cxy; 
     [MarshalAs(UnmanagedType.LPTStr)] public string pszText; 
     public IntPtr hbm; 
     public int cchTextMax; 
     public Format fmt; 
     public IntPtr lParam; 
     // _WIN32_IE >= 0x0300 
     public int iImage; 
     public int iOrder; 
     // _WIN32_IE >= 0x0500 
     public uint type; 
     public IntPtr pvFilter; 
     // _WIN32_WINNT >= 0x0600 
     public uint state; 

     [Flags] 
     public enum Mask 
     { 
      Format = 0x4,  // HDI_FORMAT 
     }; 

     [Flags] 
     public enum Format 
     { 
      SortDown = 0x200, // HDF_SORTDOWN 
      SortUp = 0x400,  // HDF_SORTUP 
     }; 
    }; 

    public const int LVM_FIRST = 0x1000; 
    public const int LVM_GETHEADER = LVM_FIRST + 31; 

    public const int HDM_FIRST = 0x1200; 
    public const int HDM_GETITEM = HDM_FIRST + 11; 
    public const int HDM_SETITEM = HDM_FIRST + 12; 

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
    public static extern IntPtr SendMessage(IntPtr hWnd, UInt32 msg, IntPtr wParam, IntPtr lParam); 

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
    public static extern IntPtr SendMessage(IntPtr hWnd, UInt32 msg, IntPtr wParam, ref HDITEM lParam); 

    public static void SetSortIcon(this ListView listViewControl, int columnIndex, SortOrder order) 
    { 
     IntPtr columnHeader = SendMessage(listViewControl.Handle, LVM_GETHEADER, IntPtr.Zero, IntPtr.Zero); 
     for (int columnNumber = 0; columnNumber <= listViewControl.Columns.Count - 1; columnNumber++) 
     { 
      var columnPtr = new IntPtr(columnNumber); 
      var item = new HDITEM 
       { 
        mask = HDITEM.Mask.Format 
       }; 

      if (SendMessage(columnHeader, HDM_GETITEM, columnPtr, ref item) == IntPtr.Zero) 
      { 
       throw new Win32Exception(); 
      } 

      if (order != SortOrder.None && columnNumber == columnIndex) 
      { 
       switch (order) 
       { 
        case SortOrder.Ascending: 
         item.fmt &= ~HDITEM.Format.SortDown; 
         item.fmt |= HDITEM.Format.SortUp; 
         break; 
        case SortOrder.Descending: 
         item.fmt &= ~HDITEM.Format.SortUp; 
         item.fmt |= HDITEM.Format.SortDown; 
         break; 
       } 
      } 
      else 
      { 
       item.fmt &= ~HDITEM.Format.SortDown & ~HDITEM.Format.SortUp; 
      } 

      if (SendMessage(columnHeader, HDM_SETITEM, columnPtr, ref item) == IntPtr.Zero) 
      { 
       throw new Win32Exception(); 
      } 
     } 
    } 
} 

Następnie można wywołać metodę rozszerzenia jak takie:

myListView.SetSortIcon(0, SortOrder.Ascending); 

To działa przy użyciu P/Wywołaj do:

  • Uzyskaj uchwyt kontrolki nagłówka dla widoku listy przy użyciu LVM_GETHEADER m eessage.
  • Uzyskaj informacje o kolumnie nagłówkowej, używając wiadomości HDM_GETITEM.
  • Następnie modyfikuje fmt, aby ustawić/wyczyścić flagi HDF_SORTDOWN i HDF_SORTUP na zwróconej strukturze HDITEM.
  • W końcu ponownie ustawia informacje z wiadomości HDM_SETITEM.

To jak to wygląda:

Arrows on a list view column

+0

Zauważ, że Application.EnableVisualStyles(); musi być wywołany, aby powyższy kod zadziałał. – Rune

+0

Nie, nie ma. Działa również w przypadku nielistylonych listView. –

+2

Podana wartość LVCOLUMN to w rzeczywistości HDITEM. Zdaję sobie sprawę, skoro sam to określasz, że to nie ma znaczenia, ale tłumacząc to na C++, pomyliłem mnie na kilka :). – Bob

4

Świetna odpowiedź przez Andrzeja. Jeśli ktoś szuka odpowiednik VB.net tutaj jest:

Public Module ListViewExtensions 
    Public Enum SortOrder 
     None 
     Ascending 
     Descending 
    End Enum 

    <StructLayout(LayoutKind.Sequential)> 
    Public Structure HDITEM 
     Public theMask As Mask 
     Public cxy As Integer 
     <MarshalAs(UnmanagedType.LPTStr)> 
     Public pszText As String 
     Public hbm As IntPtr 
     Public cchTextMax As Integer 
     Public fmt As Format 
     Public lParam As IntPtr 
     ' _WIN32_IE >= 0x0300 
     Public iImage As Integer 
     Public iOrder As Integer 
     ' _WIN32_IE >= 0x0500 
     Public type As UInteger 
     Public pvFilter As IntPtr 
     ' _WIN32_WINNT >= 0x0600 
     Public state As UInteger 

     <Flags()> 
     Public Enum Mask 
      Format = &H4  ' HDI_FORMAT 
     End Enum 


     <Flags()> 
     Public Enum Format 
      SortDown = &H200 ' HDF_SORTDOWN 
      SortUp = &H400  ' HDF_SORTUP 
     End Enum 
    End Structure 

    Public Const LVM_FIRST As Integer = &H1000 
    Public Const LVM_GETHEADER As Integer = LVM_FIRST + 31 

    Public Const HDM_FIRST As Integer = &H1200 
    Public Const HDM_GETITEM As Integer = HDM_FIRST + 11 
    Public Const HDM_SETITEM As Integer = HDM_FIRST + 12 

    <DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> 
    Public Function SendMessage(hWnd As IntPtr, msg As UInt32, wParam As IntPtr, lParam As IntPtr) As IntPtr 
    End Function 

    <DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> 
    Public Function SendMessage(hWnd As IntPtr, msg As UInt32, wParam As IntPtr, ByRef lParam As HDITEM) As IntPtr 
    End Function 

    <Extension()> 
    Public Sub SetSortIcon(listViewControl As ListView, columnIndex As Integer, order As SortOrder) 
     Dim columnHeader As IntPtr = SendMessage(listViewControl.Handle, LVM_GETHEADER, IntPtr.Zero, IntPtr.Zero) 
     For columnNumber As Integer = 0 To listViewControl.Columns.Count - 1 

      Dim columnPtr As New IntPtr(columnNumber) 
      Dim item As New HDITEM 

      item.theMask = HDITEM.Mask.Format 

      If SendMessage(columnHeader, HDM_GETITEM, columnPtr, item) = IntPtr.Zero Then Throw New Win32Exception 

      If order <> SortOrder.None AndAlso columnNumber = columnIndex Then 
       Select Case order 
        Case SortOrder.Ascending 
         item.fmt = item.fmt And Not HDITEM.Format.SortDown 
         item.fmt = item.fmt Or HDITEM.Format.SortUp 
        Case SortOrder.Descending 
         item.fmt = item.fmt And Not HDITEM.Format.SortUp 
         item.fmt = item.fmt Or HDITEM.Format.SortDown 
       End Select 
      Else 
       item.fmt = item.fmt And Not HDITEM.Format.SortDown And Not HDITEM.Format.SortUp 
      End If 

      If SendMessage(columnHeader, HDM_SETITEM, columnPtr, item) = IntPtr.Zero Then Throw New Win32Exception 
     Next 
    End Sub 
End Module 
1

Dla innych leniwy C++ (jak ja):

// possible sorting header icons/indicators 
enum class ListViewSortArrow { None, Ascending, Descending }; 

BOOL LVHeader_SetSortArrow(HWND hHeader, int nColumn, ListViewSortArrow sortArrow) 
{ 
    ASSERT(hHeader); 

    HDITEM hdrItem = { 0 }; 
    hdrItem.mask = HDI_FORMAT; 
    if (Header_GetItem(hHeader, nColumn, &hdrItem)) 
    { 
     switch (sortArrow) 
     { 
     default: 
      ASSERT(false); 
     case ListViewSortArrow::None: 
      hdrItem.fmt = hdrItem.fmt & ~(HDF_SORTDOWN | HDF_SORTUP); 
      break; 
     case ListViewSortArrow::Ascending: 
      hdrItem.fmt = (hdrItem.fmt & ~HDF_SORTDOWN) | HDF_SORTUP; 
      break; 
     case ListViewSortArrow::Descending: 
      hdrItem.fmt = (hdrItem.fmt & ~HDF_SORTUP) | HDF_SORTDOWN; 
      break; 
     } 

     return Header_SetItem(hHeader, nColumn, &hdrItem); 
    } 

    return FALSE; 
} 

BOOL ListView_SetSortArrow(HWND hListView, int nColumn, ListViewSortArrow sortArrow) 
{ 
    ASSERT(hListView); 

    if (HWND hHeader = ListView_GetHeader(hListView)) 
     return LVHeader_SetSortArrow(hHeader, nColumn, sortArrow); 

    return FALSE; 
} 
Powiązane problemy