C# - 在ObjectListView中改变分组的颜色

5
在构建ObjectListView中的分组时,我该如何更改分组的颜色?默认情况下,分组显示为深蓝色线条和深蓝色前景色。我该如何更改它?
2个回答

2
这似乎是不可能的。几年前有一次讨论,关于更改组标题字体/样式的能力。我不知道那是否仍代表实际情况,但几周前我在寻找解决方案时无法找到任何解决方法。

即使使用未记录的 ListView API,也没有机制可以更改任何关于如何呈现组标题的内容。您无法更改字体、颜色、背景颜色或其他任何东西。

嗯,在 XP 下,您可以更改组标题的颜色(通过 SetGroupMetrics 消息)。但在 Vista 及以后版本中,该功能被删除了。


0

您可以通过常规的WinForms Listview来实现此功能,如下所示:

Imports System.ComponentModel
Imports System.Drawing
Imports System.Drawing.Drawing2D
Imports System.Runtime.InteropServices
Imports System.Windows.Forms

<ToolboxItem(False)>
Public Class ListViewExt
    Inherits ListView

    Private _groupHeadingBackColor As Color = Color.Gray
    Public Property GroupHeadingBackColor() As Color
        Get
            Return _groupHeadingBackColor
        End Get
        Set(ByVal value As Color)
            _groupHeadingBackColor = value
        End Set
    End Property

    Private _groupHeadingForeColor As Color = Color.Black
    Public Property GroupHeadingForeColor() As Color
        Get
            Return _groupHeadingForeColor
        End Get
        Set(ByVal value As Color)
            _groupHeadingForeColor = value
        End Set
    End Property

    Private _groupHeadingFont As Font = Me.Font
    Public Property GroupHeadingFont() As Font
        Get
            Return _groupHeadingFont
        End Get
        Set(ByVal value As Font)
            _groupHeadingFont = value
        End Set
    End Property

    Private _separatorColor As Color
    Public Property SeparatorColor() As Color
        Get
            Return _separatorColor
        End Get
        Set(ByVal value As Color)
            _separatorColor = value
        End Set
    End Property

    Public Const LVCDI_ITEM = &H0
    Public Const LVCDI_GROUP = &H1
    Public Const LVCDI_ITEMSLIST = &H2

    Public Const LVM_FIRST = &H1000
    Public Const LVM_GETGROUPRECT = (LVM_FIRST + 98)
    Public Const LVM_ENABLEGROUPVIEW = (LVM_FIRST + 157)
    Public Const LVM_SETGROUPINFO = (LVM_FIRST + 147)
    Public Const LVM_GETGROUPINFO = (LVM_FIRST + 149)
    Public Const LVM_REMOVEGROUP = (LVM_FIRST + 150)
    Public Const LVM_MOVEGROUP = (LVM_FIRST + 151)
    Public Const LVM_GETGROUPCOUNT = (LVM_FIRST + 152)
    Public Const LVM_GETGROUPINFOBYINDEX = (LVM_FIRST + 153)
    Public Const LVM_MOVEITEMTOGROUP = (LVM_FIRST + 154)

    Public Const WM_LBUTTONUP = &H202

    <StructLayout(LayoutKind.Sequential)>
    Public Structure NMHDR
        Public hwndFrom As IntPtr
        Public idFrom As IntPtr
        Public code As Integer
    End Structure

    <StructLayout(LayoutKind.Sequential)>
    Public Structure RECT
        Public left As Integer
        Public top As Integer
        Public right As Integer
        Public bottom As Integer
    End Structure

    <StructLayout(LayoutKind.Sequential)>
    Public Structure NMCUSTOMDRAW
        Public hdr As NMHDR
        Public dwDrawStage As Integer
        Public hdc As IntPtr
        Public rc As RECT
        Public dwItemSpec As IntPtr
        Public uItemState As UInteger
        Public lItemlParam As IntPtr
    End Structure

    <StructLayout(LayoutKind.Sequential)>
    Public Structure NMLVCUSTOMDRAW
        Public nmcd As NMCUSTOMDRAW
        Public clrText As Integer
        Public clrTextBk As Integer
        Public iSubItem As Integer
        Public dwItemType As Integer
        Public clrFace As Integer
        Public iIconEffect As Integer
        Public iIconPhase As Integer
        Public iPartId As Integer
        Public iStateId As Integer
        Public rcText As RECT
        Public uAlign As UInteger
    End Structure

    <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode)>
    Public Structure LVGROUP
        Public cbSize As UInteger
        Public mask As UInteger
        '<MarshalAs(UnmanagedType.LPTStr)>
        'Public pszHeader As String
        Public pszHeader As IntPtr
        Public cchHeader As Integer
        '<MarshalAs(UnmanagedType.LPTStr)>
        'Public pszFooter As String
        Public pszFooter As IntPtr
        Public cchFooter As Integer
        Public iGroupId As Integer
        Public stateMask As UInteger
        Public state As UInteger
        Public uAlign As UInteger

        '<MarshalAs(UnmanagedType.LPTStr)>
        'Public pszSubtitle As String
        Public pszSubtitle As IntPtr
        Public cchSubtitle As UInteger
        '<MarshalAs(UnmanagedType.LPTStr)>
        'Public pszTask As String
        Public pszTask As IntPtr
        Public cchTask As UInteger
        '<MarshalAs(UnmanagedType.LPTStr)>
        'Public pszDescriptionTop As String
        Public pszDescriptionTop As IntPtr
        Public cchDescriptionTop As UInteger
        '<MarshalAs(UnmanagedType.LPTStr)>
        'Public pszDescriptionBottom As String
        Public pszDescriptionBottom As IntPtr
        Public cchDescriptionBottom As UInteger
        Public iTitleImage As Integer
        Public iExtendedImage As Integer
        Public iFirstItem As Integer
        Public cItems As UInteger
        '<MarshalAs(UnmanagedType.LPTStr)>
        'Public pszSubsetTitle As String
        Public pszSubsetTitle As IntPtr
        Public cchSubsetTitle As UInteger
    End Structure


    <Flags>
    Public Enum CDRF
        CDRF_DODEFAULT = &H0
        CDRF_NEWFONT = &H2
        CDRF_SKIPDEFAULT = &H4
        CDRF_DOERASE = &H8
        CDRF_SKIPPOSTPAINT = &H100
        CDRF_NOTIFYPOSTPAINT = &H10
        CDRF_NOTIFYITEMDRAW = &H20
        CDRF_NOTIFYSUBITEMDRAW = &H20
        CDRF_NOTIFYPOSTERASE = &H40
    End Enum

    <Flags>
    Public Enum CDDS
        CDDS_PREPAINT = &H1
        CDDS_POSTPAINT = &H2
        CDDS_PREERASE = &H3
        CDDS_POSTERASE = &H4
        CDDS_ITEM = &H10000
        CDDS_ITEMPREPAINT = (CDDS_ITEM Or CDDS_PREPAINT)
        CDDS_ITEMPOSTPAINT = (CDDS_ITEM Or CDDS_POSTPAINT)
        CDDS_ITEMPREERASE = (CDDS_ITEM Or CDDS_PREERASE)
        CDDS_ITEMPOSTERASE = (CDDS_ITEM Or CDDS_POSTERASE)
        CDDS_SUBITEM = &H20000
    End Enum

    Public Const LVGF_NONE = &H0
    Public Const LVGF_HEADER = &H1
    Public Const LVGF_FOOTER = &H2
    Public Const LVGF_STATE = &H4
    Public Const LVGF_ALIGN = &H8
    Public Const LVGF_GROUPID = &H10

    Public Const LVGF_SUBTITLE = &H100 'pszSubtitle is valid
    Public Const LVGF_TASK = &H200 'pszTask is valid
    Public Const LVGF_DESCRIPTIONTOP = &H400 'pszDescriptionTop is valid
    Public Const LVGF_DESCRIPTIONBOTTOM = &H800 'pszDescriptionBottom is valid
    Public Const LVGF_TITLEIMAGE = &H1000 'iTitleImage is valid
    Public Const LVGF_EXTENDEDIMAGE = &H2000 'iExtendedImage is valid
    Public Const LVGF_ITEMS = &H4000 'iFirstItem and cItems are valid
    Public Const LVGF_SUBSET = &H8000 'pszSubsetTitle is valid
    Public Const LVGF_SUBSETITEMS = &H10000 'readonly, cItems holds count of items in visible subset, iFirstItem is valid

    Public Const LVGS_NORMAL = &H0
    Public Const LVGS_COLLAPSED = &H1
    Public Const LVGS_HIDDEN = &H2
    Public Const LVGS_NOHEADER = &H4
    Public Const LVGS_COLLAPSIBLE = &H8
    Public Const LVGS_FOCUSED = &H10
    Public Const LVGS_SELECTED = &H20
    Public Const LVGS_SUBSETED = &H40
    Public Const LVGS_SUBSETLINKFOCUSED = &H80

    Public Const LVGA_HEADER_LEFT = &H1
    Public Const LVGA_HEADER_CENTER = &H2
    Public Const LVGA_HEADER_RIGHT = &H4 'Don't forget to validate exclusivity
    Public Const LVGA_FOOTER_LEFT = &H8
    Public Const LVGA_FOOTER_CENTER = &H10
    Public Const LVGA_FOOTER_RIGHT = &H20 'Don't forget to validate exclusivity

    Public Const LVGGR_GROUP = 0 ' Entire expanded group
    Public Const LVGGR_HEADER = 1  ' Header only (collapsed group)
    Public Const LVGGR_LABEL = 2  ' Label only
    Public Const LVGGR_SUBSETLINK = 3  'subset link only

    <DllImport("User32.dll", EntryPoint:="SendMessageW", SetLastError:=True)>
    Public Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal Msg As Integer, ByVal wParam As Integer, ByRef lParam As IntPtr) As Integer
    End Function

    <DllImport("User32.dll", EntryPoint:="SendMessageW", SetLastError:=True)>
    Public Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal Msg As Integer, ByVal wParam As Integer, ByRef lParam As LVGROUP) As Integer
    End Function

    <DllImport("User32.dll", EntryPoint:="SendMessageW", SetLastError:=True)>
    Public Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal Msg As Integer, ByVal wParam As Integer, ByRef lParam As RECT) As Integer
    End Function

    <DllImport("User32.dll", EntryPoint:="PostMessageW", SetLastError:=True)>
    Public Shared Function PostMessage(ByVal hWnd As IntPtr, ByVal Msg As Integer, ByVal wParam As Integer, ByRef lParam As IntPtr) As Integer
    End Function

    Public Function SetGroupInfo(ByVal hWnd As IntPtr, nGroupID As Integer, nSate As UInteger) As Integer
        Dim lvg As LVGROUP = New LVGROUP()
        lvg.cbSize = CUInt(Marshal.SizeOf(lvg))
        lvg.mask = LVGF_STATE Or LVGF_GROUPID Or LVGF_HEADER
        ' for test
        Dim nRet2 As Integer = SendMessage(hWnd, LVM_GETGROUPINFO, nGroupID, lvg)

        lvg.state = nSate
        lvg.mask = LVGF_STATE
        nRet2 = SendMessage(hWnd, LVM_SETGROUPINFO, nGroupID, lvg)
        Return -1
    End Function

    Protected Overrides Sub WndProc(ByRef m As Message)
        If m.Msg = WM_REFLECT + WM_NOFITY Then
            Dim pnmhdr = CType(m.GetLParam(GetType(NMHDR)), NMHDR)
            If pnmhdr.code = NM_CUSTOMDRAW Then
                Dim pnmlv = CType(m.GetLParam(GetType(NMLVCUSTOMDRAW)), NMLVCUSTOMDRAW)
                Select Case pnmlv.nmcd.dwDrawStage
                    Case CDDS.CDDS_PREPAINT
                        If (pnmlv.dwItemType = LVCDI_GROUP) Then
                            Dim rectHeader As RECT = New RECT()
                            rectHeader.top = LVGGR_HEADER
                            Dim nItem As Integer = CInt(pnmlv.nmcd.dwItemSpec)
                            'If (nItem = 0) Then
                            Dim nRet As Integer = SendMessage(m.HWnd, LVM_GETGROUPRECT, nItem, rectHeader)
                            Using g As Graphics = Graphics.FromHdc(pnmlv.nmcd.hdc)


                                Dim rect As New Rectangle(rectHeader.left, rectHeader.top, rectHeader.right - rectHeader.left, rectHeader.bottom - rectHeader.top)

                                'Dim linGrBrush As New LinearGradientBrush(New System.Drawing.Point(0, 0), New System.Drawing.Point(rectHeader.right, rectHeader.bottom), Color.Blue, Color.LightCyan)
                                Dim BgBrush As New SolidBrush(_groupHeadingBackColor)
                                g.FillRectangle(BgBrush, rect)

                                Dim lvg As LVGROUP = New LVGROUP()
                                lvg.cbSize = CUInt(Marshal.SizeOf(lvg))
                                lvg.mask = LVGF_STATE Or LVGF_GROUPID Or LVGF_HEADER
                                Dim nRet2 As Integer = SendMessage(m.HWnd, LVM_GETGROUPINFO, nItem, lvg)
                                Dim sText = Marshal.PtrToStringUni(lvg.pszHeader)

                                Dim textSize As SizeF = g.MeasureString(sText, _groupHeadingFont)

                                Dim RectHeightMiddle As Integer = CInt((rect.Height - textSize.Height) / 2)

                                rect.Offset(10, RectHeightMiddle)

                                Using drawBrush As New SolidBrush(_groupHeadingForeColor)

                                    g.DrawString(sText, _groupHeadingFont, drawBrush, rect)
                                    rect.Offset(0, -RectHeightMiddle)

                                    Using lineBrush As New SolidBrush(_separatorColor)
                                        g.DrawLine(New Pen(lineBrush), rect.X + g.MeasureString(sText, _groupHeadingFont).Width + 10,
                                                                    rect.Y + CInt(rect.Height / 2),
                                                                    rect.X + CInt(rect.Width * 95 / 100),
                                                                    rect.Y + CInt(rect.Height / 2))

                                    End Using
                                End Using
                            End Using
                            m.Result = New IntPtr(CDRF.CDRF_SKIPDEFAULT)
                            'End If
                        Else
                            m.Result = New IntPtr(CDRF.CDRF_NOTIFYITEMDRAW)
                        End If
                    Case CDDS.CDDS_ITEMPREPAINT
                        m.Result = New IntPtr(CDRF.CDRF_NOTIFYSUBITEMDRAW Or CDRF.CDRF_NOTIFYPOSTPAINT)
                    Case CDDS.CDDS_ITEMPOSTPAINT
                End Select
            End If
            Return
        Else
            MyBase.WndProc(m)
        End If
    End Sub

    Private Const NM_FIRST As Integer = 0
    Private Const NM_CLICK As Integer = NM_FIRST - 2
    Private Const NM_CUSTOMDRAW As Integer = NM_FIRST - 12
    Private Const WM_REFLECT As Integer = &H2000
    Private Const WM_NOFITY As Integer = &H4E
End Class

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接