代码之家  ›  专栏  ›  技术社区  ›  Andrew Moore

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

  •  39
  • Andrew Moore  · 技术社区  · 16 年前

    3 回复  |  直到 16 年前
        1
  •  71
  •   Justin    12 年前

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

    [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来:

    Arrows on a list view column

        2
  •  7
  •   Alex Essilfie    7 年前

    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
    
        3
  •  4
  •   Mordachai    7 年前

    对于任何其他懒惰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;
    }
    
        4
  •  3
  •   symbiont    5 年前

    您可以折衷并使用看起来像箭头的字符(我使用charmap选择它们),而不是与Windows API混为一谈

    private void SetSortArrow(ColumnHeader head, SortOrder order)
    {
        const string ascArrow = " ▲";
        const string descArrow = " ▼";
    
        // remove arrow
        if(head.Text.EndsWith(ascArrow) || head.Text.EndsWith(descArrow))
            head.Text = head.Text.Substring(0, head.Text.Length-2);
    
        // add arrow
        switch (order)
        {
            case SortOrder.Ascending: head.Text += ascArrow; break;
            case  SortOrder.Descending: head.Text += descArrow; break;
        }
    }
    
    SetSortArrow(listView1.Columns[0], SortOrder.None);       // remove arrow from first column if present
    SetSortArrow(listView1.Columns[1], SortOrder.Ascending);  // set second column arrow to ascending
    SetSortArrow(listView1.Columns[1], SortOrder.Descending); // set second column arrow to descending