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

WinForms部分控件OnPaint重写方法未触发的问题求助

自定义WinForms控件OnPaint方法无法触发

我遇到一个问题:OnPaint方法在Button控件中能正常工作,但在DateTimePicker、TextBox、ProgressBar或者我测试的ComboBox控件里完全不会触发,在OnPaint上设断点也根本不会命中。我试过按照旧教程里的方法设置ControlStyles,但没有任何效果。

测试代码如下:

Public Class Form2
    
    Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load

        Me.SetStyle(ControlStyles.AllPaintingInWmPaint, True)
        Me.SetStyle(ControlStyles.UserPaint, True)
        Me.SetStyle(ControlStyles.OptimizedDoubleBuffer, True)
        Me.SetStyle(ControlStyles.ResizeRedraw, True)

        Dim customComboBox1 As New CustomComboBox()
        customComboBox1.Location = New Point(50, 50)

        Me.Controls.Add(customComboBox1)

        customComboBox1.Invalidate()

    End Sub

End Class

Imports System.Windows.Forms

Public Class CustomComboBox
    Inherits ComboBox

    Protected Overrides Sub OnPaint(e As PaintEventArgs)
        MyBase.OnPaint(e)
        Dim rectanglePen As New Pen(Color.Black, 2)
        e.Graphics.DrawRectangle(rectanglePen, New Rectangle(0, 0, Width - 1, Height - 1))
        rectanglePen.Dispose()
    End Sub

End Class

解决方案

WinForms里像ComboBox、DateTimePicker、TextBox这类控件属于原生Windows控件(也叫“封装控件”),它们的绘制逻辑由系统直接接管,默认不会触发UserPaint相关逻辑,哪怕设置了ControlStyles.UserPaint也没用。针对这类控件,有几种可行的自定义绘制思路:

1. 开启控件自绘模式(仅部分控件支持)

比如ComboBox,必须先设置DrawMode属性为OwnerDrawFixed或OwnerDrawVariable,控件才会触发自绘相关的方法:

Public Class CustomComboBox
    Inherits ComboBox
    Public Sub New()
        ' 开启自绘模式是前提
        Me.DrawMode = DrawMode.OwnerDrawFixed
        ' 开启必要的绘制样式
        Me.SetStyle(ControlStyles.AllPaintingInWmPaint Or ControlStyles.UserPaint Or ControlStyles.OptimizedDoubleBuffer, True)
    End Sub

    Protected Overrides Sub OnPaint(e As PaintEventArgs)
        MyBase.OnPaint(e)
        ' 使用Using自动释放资源,避免内存泄漏
        Using rectanglePen As New Pen(Color.Black, 2)
            e.Graphics.DrawRectangle(rectanglePen, New Rectangle(0, 0, Width - 1, Height - 1))
        End Using
    End Sub
End Class

注意:TextBox、DateTimePicker这类控件不支持这种方式,它们的自绘限制更严格。

2. 重写WndProc拦截绘制消息

对于无法直接开启自绘的控件,比如TextBox、DateTimePicker,可以通过拦截Windows的WM_PAINT消息来实现自定义绘制:
以TextBox为例:

Public Class CustomTextBox
    Inherits TextBox
    Protected Overrides Sub WndProc(ByRef m As Message)
        MyBase.WndProc(m)
        ' 拦截WM_PAINT消息(消息编号&HF)
        If m.Msg = &HF Then
            Using g As Graphics = Me.CreateGraphics()
                Using pen As New Pen(Color.Red, 2)
                    ' 在原生绘制基础上叠加自定义边框
                    g.DrawRectangle(pen, New Rectangle(0, 0, Me.Width - 1, Me.Height - 1))
                End Using
            End Using
        End If
    End Sub
End Class

如果想完全替换原生绘制逻辑,可以去掉MyBase.WndProc(m),但这样需要自己实现控件的所有绘制和交互逻辑,复杂度很高,一般只建议在简单需求下叠加绘制。

3. 替代方案:使用无原生依赖的自定义控件

如果自定义绘制需求复杂,也可以选择完全从头实现一个控件,或者使用第三方WinForms控件库,避开原生控件的绘制限制。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 02:46:29