改变ObjectListView中组的颜色
本文关键字:颜色 ObjectListView 改变 | 更新日期: 2023-09-27 18:13:59
在ObjectListView中构建组时,如何更改组的颜色?在默认情况下,组以深蓝色前色调的深蓝色线显示。我怎样才能改变呢?
这显然不可能。几年前有一个关于改变组标题字体/样式的讨论。我不知道这是否仍然代表实际情况,但是当我几个星期前寻找它的时候,我没能想出一个解决方案。
即使使用未记录的ListView API,也没有机制可以改变关于组标题如何渲染的任何内容。你不能改变字体,颜色,背景色,任何颜色
只在XP下,你可以改变组头的颜色(通过SetGroupMetrics消息)。但是在Vista及以后的版本中,这个功能被取消了。
您可以使用常规的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