You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

VB.NET自定义ComboBox设为DropdownStyle=Dropdown时显示黑色的非WndProc解决方法

VB.NET自定义ComboBox Dropdown样式显示黑色的解决方法(不使用WndProc)

问题描述

开发自定义ComboBox组件时,将DropdownStyle设置为Dropdown时组件显示黑色,设置为DropDownList时显示正常,需在不使用WndProc的前提下解决该问题。

提供的自定义ComboBox代码

Imports System.ComponentModel
Imports System.Drawing.Drawing2D

Public Class FLATCOMBOBOX
    Inherits ComboBox
    ' Fields
    Private _disabledIndicatorColor As Color = Color.DarkGray
    Private _disabledColor As Color = Color.FromArgb(240, 240, 240)
    Private _disabledForeColor As Color = Color.FromArgb(&H6D, &H6D, &H6D)
    Private _disabledBorderColor As Color = Color.FromArgb(&HCC, &HCC, &HCC)
    Private _itemTopMargin As Integer = 1
    Private _textLeftMargin As Integer = 5
    Private _borderColor As Color = Color.Red
    Private _backColor As Color = Color.White
    Private _radius As Integer = 1
    Private _borderthickness As BorderThickness
    Private _indicatorColor As Color = Color.Red
    ' Methods
    Public Sub New()
        Me.InitializeComponent()
        MyBase.SetStyle(ControlStyles.AllPaintingInWmPaint, True)
        MyBase.SetStyle(ControlStyles.ContainerControl, True)
        MyBase.SetStyle(ControlStyles.OptimizedDoubleBuffer, True)
        MyBase.SetStyle(ControlStyles.ResizeRedraw, True)
        MyBase.SetStyle(ControlStyles.Selectable, True)
        MyBase.SetStyle(ControlStyles.UserPaint, True)
        MyBase.SetStyle(ControlStyles.Selectable, True)
        MyBase.SetStyle(ControlStyles.SupportsTransparentBackColor, True)
        Me.FlatStyle = FlatStyle.Flat
        Me.DrawMode = DrawMode.Normal
        Me.DropDownStyle = ComboBoxStyle.DropDown
        Me.Width = 260
        Me.Height = &H20
        Me.ItemHeight = &H1A
        Me.DrawMode = DrawMode.OwnerDrawFixed
        Me.IndicatorColor = Color.Red
        Me.DropdownBorderThickness = BorderThickness.Thin
    End Sub
    Private Sub DrawIndicator(ByVal graphics As Graphics, ByVal lineColor As Color, ByVal indicatorColor As Color, ByVal foreColor As Color)
        Dim num As Integer
        Dim pen As Pen
        graphics.SmoothingMode = SmoothingMode.AntiAlias
        graphics.SmoothingMode = SmoothingMode.HighQuality
        graphics.InterpolationMode = InterpolationMode.High
        Dim brush As New SolidBrush(Me._borderColor)
        Dim brush2 As New SolidBrush(Me._backColor)
        If Not Me.Enabled Then
            indicatorColor = Me._disabledIndicatorColor
            brush.Color = Me._disabledBorderColor
            brush2.Color = Me._disabledColor
        End If
        If Me.DropdownBorderThickness = BorderThickness.Thick Then
            pen = New Pen(brush, 2.0F)
            num = 1
        Else
            pen = New Pen(brush, 1.0F)
            num = 0
        End If
        Using p = New Pen(Me.BorderColor, 2)
            graphics.DrawRectangle(p, MyBase.ClientRectangle.X, MyBase.ClientRectangle.Y, MyBase.ClientRectangle.Width - 1, MyBase.ClientRectangle.Height - 1)
        End Using
        brush.Dispose()
        brush2.Dispose()
        pen.Dispose()
    End Sub
    <Category("Tools"), Description("Sets dropdown's border color.")>
    Public Overridable Property BorderColor As Color
        Get
            Return Me._borderColor
        End Get
        Set(ByVal value As Color)
            Me._borderColor = value
            Me.Refresh()
        End Set
    End Property
    <DisplayName("BackColor"), Category("Tools"), Description("Sets the dropdown's background color.")>
    Public Overridable Property BackgroundColor As Color
        Get
            Return Me._backColor
        End Get
        Set(ByVal value As Color)
            Me._backColor = value
            Me.Refresh()
        End Set
    End Property
    <Category("Tools"), Description("Sets the dropdown's border thickness.")>
    Public Overridable Property DropdownBorderThickness As BorderThickness
        Get
            Return Me._borderthickness
        End Get
        Set(ByVal value As Color)
            Me._borderthickness = value
            Me.Refresh()
        End Set
    End Property
    <Category("Tools"), Description("Sets the indicator color.")>
    Public Overridable Property IndicatorColor As Color
        Get
            Return Me._indicatorColor
        End Get
        Set(ByVal value As Color)
            Me._indicatorColor = value
            Me.Refresh()
        End Set
    End Property
    <Browsable(False)>
    Public Overridable Property Color As Color
        Get
            Return Me._borderColor
        End Get
        Set(ByVal value As Color)
            Me._borderColor = value
            Me.Refresh()
        End Set
    End Property

    Protected Overrides Sub OnPaint(ByVal pe As PaintEventArgs)
        If Me.Enabled Then
            Me.DrawIndicator(pe.Graphics, Me.Color, Me.IndicatorColor, Me.ForeColor)
        Else
            Me.DrawIndicator(pe.Graphics, Me._disabledBorderColor, Me._disabledBorderColor, Me._disabledForeColor)
        End If
        MyBase.OnPaint(pe)
    End Sub
    Public Enum BorderThickness
        Thick
        Thin
    End Enum
End Class

解决方案

问题核心:当DropdownStyle为Dropdown时,ComboBox内部包含可编辑TextBox,开启UserPaint后未主动绘制控件背景,且原生BackColor未与自定义背景同步,导致未绘制区域显示GDI+默认黑色。

修复步骤

  1. 在OnPaint中提前填充控件背景
    修改OnPaint方法,先填充整个客户端区域背景色,覆盖默认黑色:

    Protected Overrides Sub OnPaint(ByVal pe As PaintEventArgs)
        ' 先填充背景色,避免黑色区域透出
        Using bgBrush As New SolidBrush(If(Me.Enabled, Me._backColor, Me._disabledColor))
            pe.Graphics.FillRectangle(bgBrush, MyBase.ClientRectangle)
        End Using
        
        If Me.Enabled Then
            Me.DrawIndicator(pe.Graphics, Me.Color, Me.IndicatorColor, Me.ForeColor)
        Else
            Me.DrawIndicator(pe.Graphics, Me._disabledBorderColor, Me._disabledBorderColor, Me._disabledForeColor)
        End If
        MyBase.OnPaint(pe)
    End Sub
    
  2. 同步原生BackColor与自定义BackgroundColor
    在BackgroundColor属性的Set方法中同步原生BackColor,确保内部TextBox背景与控件一致:

    <DisplayName("BackColor"), Category("Tools"), Description("Sets the dropdown's background color.")>
    Public Overridable Property BackgroundColor As Color
        Get
            Return Me._backColor
        End Get
        Set(ByVal value As Color)
            Me._backColor = value
            MyBase.BackColor = value ' 同步原生BackColor
            Me.Refresh()
        End Set
    End Property
    

    同时在构造函数中初始化时添加同步:

    Public Sub New()
        ' ...原有代码
        Me._backColor = Color.White
        MyBase.BackColor = Me._backColor ' 初始化时同步
        ' ...原有代码
    End Sub
    
  3. 清理DrawIndicator中的冗余代码
    移除未使用的对象,优化边框绘制逻辑:

    Private Sub DrawIndicator(ByVal graphics As Graphics, ByVal lineColor As Color, ByVal indicatorColor As Color, ByVal foreColor As Color)
        graphics.SmoothingMode = SmoothingMode.HighQuality
        graphics.InterpolationMode = InterpolationMode.HighQualityBicubic
        
        Dim borderColor As Color = If(Me.Enabled, Me._borderColor, Me._disabledBorderColor)
        Dim borderWidth As Single = If(Me.DropdownBorderThickness = BorderThickness.Thick, 2.0F, 1.0F)
        
        ' 调整矩形避免边框被裁剪
        Dim rect As New Rectangle(
            MyBase.ClientRectangle.X + CInt(borderWidth / 2),
            MyBase.ClientRectangle.Y + CInt(borderWidth / 2),
            MyBase.ClientRectangle.Width - borderWidth,
            MyBase.ClientRectangle.Height - borderWidth
        )
        
        Using borderPen As New Pen(borderColor, borderWidth)
            graphics.DrawRectangle(borderPen, rect)
        End Using
    End Sub
    

内容的提问来源于stack exchange,提问作者dlaksmi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 01:05:22