如何使用C#在列表视图列的标题中显示sorting箭头?

如何在列表视图中显示按sorting列的标题中的sorting箭头,该列表视图遵循操作系统的本机外观?

您可以使用以下扩展方法将sorting箭头设置为特定列:

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

然后,你可以调用这样的扩展方法:

 myListView.SetSortIcon(0, SortOrder.Ascending); 

它通过使用P / Invoke来工作:

  • 使用LVM_GETHEADER消息获取列表视图的标题控件的句柄。
  • 使用HDM_GETITEM消息获取有关标题列的信息。
  • 然后它修改fmt来设置/清除返回的HDITEM结构上的HDF_SORTDOWNHDF_SORTUP标志。
  • 最后它重新设置使用HDM_SETITEM消息的信息。

这是它的样子:

列表视图列上的箭头

Andrew很好的回答。 如果任何人都在这里寻找VB.net等价物,它是:

 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 

对于其他懒惰的C ++程序员(像我):

 // 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; }