vb.net - 更改组合框下拉列表的边框颜色
问题描述
我的代码:
Private Sub ComboBox2_DrawItem(sender As Object, e As DrawItemEventArgs) Handles ComboBox2.DrawItem
If e.Index < 0 Then
Return
End If
e.Graphics.TextRenderingHint = Drawing.Text.TextRenderingHint.AntiAlias
Dim CB As ComboBox = TryCast(sender, ComboBox)
If (e.State And DrawItemState.Selected) = DrawItemState.Selected Then
e.Graphics.FillRectangle(New SolidBrush(Color.DarkRed), e.Bounds)
Else
e.Graphics.FillRectangle(New SolidBrush(CB.BackColor), e.Bounds)
End If
e.Graphics.DrawString(CB.Items(e.Index).ToString(), e.Font, New SolidBrush(CB.ForeColor), New Point(e.Bounds.X, e.Bounds.Y))
End Sub
结果(注意蓝色边缘,我要更改的内容):
解决方案
要改变ComboBox的DropDown List的Theme边框颜色,需要处理List Control的WM_NCPAINT消息,该消息在需要绘制非客户区时发送到Window的句柄:通常,当显示下拉。
要获取 ComboBox 的 List Control 的句柄,可以使用GetComboBoxInfo()函数:其 List Control 和 Edit Control 的句柄在 COMBOBOXINFO 结构中返回。
然后,您可以将 List Control 句柄分配给NativeWindow,这样您就可以覆盖它的 WndProc 和 trap WM_NCPAINT
。
收到消息后,使用GetWindowDc()HDC
函数获取列表控件的设备上下文 ()的句柄并将其传递给Graphics.FromHdc()方法,以创建可用于绘制的 Graphics 对象这个表面。
▶ 阅读有关WM_NCPAINT
消息的文档,您可能会注意到WPARAM
应该引用更新区域句柄:但它通常是 IntPtr.Zero,这就是我们需要的原因GetWindowDc()
。
在(重要)之后调用ReleaseDC()释放设备上下文的句柄。
差不多就是这样。
自定义组合框控件公开了一个公共ListBorderColor
属性,用于在设计时和运行时设置列表控件边框的颜色。
Imports System.ComponentModel
Imports System.Drawing
Imports System.Runtime.InteropServices
Imports System.Windows.Forms
<DesignerCategory("code")>
Public Class ComboBoxExt
Inherits ComboBox
Private listControl As ListNativeWindow = Nothing
Private m_ListBorderColor As Color = Color.Transparent
Public Sub New()
End Sub
<DefaultValue(GetType(Color), "Transparent")>
Public Property ListBorderColor As Color
Get
Return m_ListBorderColor
End Get
Set
m_ListBorderColor = Value
If listControl IsNot Nothing Then
listControl.BorderColor = m_ListBorderColor
End If
End Set
End Property
Protected Overrides Sub OnHandleCreated(e As EventArgs)
MyBase.OnHandleCreated(e)
listControl = New ListNativeWindow(GetComboBoxListInternal(Me.Handle))
listControl.BorderColor = ListBorderColor
End Sub
Protected Overrides Sub OnHandleDestroyed(e As EventArgs)
listControl.ReleaseHandle()
MyBase.OnHandleDestroyed(e)
End Sub
Public Class ListNativeWindow
Inherits NativeWindow
Public Sub New()
Me.New(IntPtr.Zero)
End Sub
Public Sub New(hWnd As IntPtr)
If hWnd <> IntPtr.Zero Then AssignHandle(hWnd)
End Sub
Public Property BorderColor As Color = Color.Transparent
Protected Overrides Sub WndProc(ByRef m As Message)
MyBase.WndProc(m)
Select Case m.Msg
Case WM_NCPAINT
Dim hDC As IntPtr = GetWindowDC(Me.Handle)
Try
Using g = Graphics.FromHdc(hDC),
pen = New Pen(BorderColor)
Dim rect = g.VisibleClipBounds
g.DrawRectangle(pen, 0, 0, rect.Width - 1, rect.Height - 1)
End Using
Finally
ReleaseDC(Me.Handle, hDC)
End Try
m.Result = IntPtr.Zero
End Select
End Sub
End Class
<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Unicode)>
Friend Shared Function GetComboBoxInfo(hWnd As IntPtr, ByRef pcbi As COMBOBOXINFO) As Boolean
End Function
<DllImport("user32.dll", SetLastError:=True)>
Friend Shared Function GetWindowDC(hWnd As IntPtr) As IntPtr
End Function
<DllImport("user32.dll", SetLastError:=True)>
Friend Shared Function ReleaseDC(hWnd As IntPtr, hDc As IntPtr) As Boolean
End Function
Friend Const WM_NCPAINT As Integer = &H85
<StructLayout(LayoutKind.Sequential)>
Friend Structure COMBOBOXINFO
Public cbSize As Integer
Public rcItem As Rectangle
Public rcButton As Rectangle
Public buttonState As Integer
Public hwndCombo As IntPtr
Public hwndEdit As IntPtr
Public hwndList As IntPtr
Public Sub Init()
cbSize = Marshal.SizeOf(Of COMBOBOXINFO)()
End Sub
End Structure
Friend Function GetComboBoxListInternal(cboHandle As IntPtr) As IntPtr
Dim cbInfo = New COMBOBOXINFO()
cbInfo.Init()
GetComboBoxInfo(cboHandle, cbInfo)
Return cbInfo.hwndList
End Function
End Class
推荐阅读
- wpf - 通过命令将 RadGrid 置于插入模式
- python - 我对算法的时间复杂度感到困惑
- c - 将所有非空元素向左移动
- c++ - C++;这是确保正确数据成员初始化的正确方法吗?
- sql - 使用 go 和 pq 驱动程序将文本附加到列
- julia - 如何指定我在函数中返回 4 Int32 的向量?
- sql-server - SQL Server TRY/CATCH 中的内部消息
- javascript - Kartik gridview,浮动标题thead和tbody不一样,yii2
- android - 错误:程序类型已存在:android.support.v4.app.INotificationSideChannel$Stub
- javascript - 如何从另一个域获取 Azuracast 的歌曲信息?