Override the drawing of some .Net Framework controls to change its border color?

前端 未结 2 455
野的像风
野的像风 2021-01-21 22:53

SCENARIO

I\'m using a 3rd party windows visual theme.

When I see my application, it looks like this:

相关标签:
2条回答
  • 2021-01-21 23:24

    VB.Net solution for ComboBox with border (is not complete, it needs to be improved with a 3dBorder)

    #Region " Option Statements "
    
    Option Explicit On
    Option Strict On
    Option Infer Off
    
    #End Region
    
    #Region " Imports "
    
    Imports System.ComponentModel
    
    #End Region
    
    ''' <summary>
    ''' A custom <see cref="ComboBox"/> user control.
    ''' </summary>
    Public Class ElektroComboBox : Inherits ComboBox
    
    #Region " Properties "
    
        ''' <summary>
        ''' Gets or sets the border color.
        ''' </summary>
        ''' <value>The border color.</value>
        <Category("Appearance")>
        Public Property BorderColor() As Color
            Get
                Return borderColor1
            End Get
            Set(ByVal value As Color)
                Me.borderColor1 = value
                Me.Invalidate()
            End Set
        End Property
        ''' <summary>
        ''' The border color.
        ''' </summary>
        Private borderColor1 As Color = SystemColors.ControlDark
    
        ''' <summary>
        ''' Gets or sets the border style.
        ''' </summary>
        ''' <value>The border color.</value>
        <Category("Appearance")>
        Public Property BorderStyle As ButtonBorderStyle
            Get
                Return borderStyle1
            End Get
            Set(ByVal value As ButtonBorderStyle)
                Me.borderStyle1 = value
                Me.Invalidate()
            End Set
        End Property
        ''' <summary>
        ''' The border style.
        ''' </summary>
        Private borderStyle1 As ButtonBorderStyle = ButtonBorderStyle.Solid
    
    #End Region
    
    #Region " Enumerations "
    
        ''' <summary>
        ''' Specifies a Windows Message.
        ''' </summary>
        Private Enum WindowsMessages
    
            WM_PAINT = &HF
    
        End Enum
    
    #End Region
    
    #Region " Windows Procedure "
    
        ''' <summary>
        ''' Processes Windows messages.
        ''' </summary>
        ''' <param name="m">The Windows <see cref="T:System.Windows.Forms.Message"/> to process.</param>
        Protected Overrides Sub WndProc(ByRef m As Message)
    
            MyBase.WndProc(m)
    
            Select Case m.Msg
    
                Case WindowsMessages.WM_PAINT
                    Me.DrawBorder()
    
            End Select
    
        End Sub
    
    #End Region
    
    #Region " Private Methods "
    
        ''' <summary>
        ''' Draws a border on the control surface.
        ''' </summary>
        Private Sub DrawBorder()
    
            Using g As Graphics = Graphics.FromHwnd(Me.Handle)
    
                ControlPaint.DrawBorder(Graphics.FromHwnd(Me.Handle), Me.ClientRectangle, Me.borderColor1, Me.borderStyle1)
    
            End Using
    
        End Sub
    
    #End Region
    
    End Class
    

    VB.Net solution for GroupBox with border (is not complete, it redraws the contained controls in a wrong way at design mode)

    #Region " Option Statements "
    
    Option Explicit On
    Option Strict On
    Option Infer Off
    
    #End Region
    
    #Region " Imports "
    
    Imports System.ComponentModel
    
    #End Region
    
    #Region " ElektroGroupBox "
    
    ''' <summary>
    ''' A custom <see cref="GroupBox"/> user control.
    ''' </summary>
    Public Class ElektroGroupBox : Inherits GroupBox
    
    #Region " Properties "
    
        ''' <summary>
        ''' Gets or sets the border color.
        ''' </summary>
        ''' <value>The border color.</value>
        <Category("Appearance")>
        Public Property BorderColor As Color
            Get
                Return Me.borderColor1
            End Get
            Set(ByVal value As Color)
                Me.borderColor1 = value
                Me.Invalidate()
            End Set
        End Property
        ''' <summary>
        ''' The border color.
        ''' </summary>
        Private borderColor1 As Color = SystemColors.ControlDark
    
        ''' <summary>
        ''' Gets or sets the border style.
        ''' </summary>
        ''' <value>The border color.</value>
        <Category("Appearance")>
        Public Property BorderStyle As ButtonBorderStyle
            Get
                Return borderStyle1
            End Get
            Set(ByVal value As ButtonBorderStyle)
                Me.borderStyle1 = value
                Me.Invalidate()
            End Set
        End Property
        ''' <summary>
        ''' The border style.
        ''' </summary>
        Private borderStyle1 As ButtonBorderStyle = ButtonBorderStyle.Solid
    
    #End Region
    
    #Region " Events "
    
        ''' <summary>
        ''' Handles the <see cref="E:Paint"/> event.
        ''' </summary>
        ''' <param name="e">A <see cref="T:PaintEventArgs"/> that contains the event data.</param>
        Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
    
            '  MyBase.OnPaint(e)
            Me.DrawBorder(e)
    
        End Sub
    
    #End Region
    
    #Region " Private Methods "
    
        ''' <summary>
        ''' Draws a border on the control surface.
        ''' </summary>
        Private Sub DrawBorder(ByVal e As PaintEventArgs)
    
            ' The groupbox header text size.
            Dim textSize As Size = TextRenderer.MeasureText(Me.Text, Me.Font)
    
            ' The width of the blankspace drawn at the right side of the text.
            Dim blankWidthSpace As Integer = 3
    
            ' The thex horizontal offset.
            Dim textOffset As Integer = 7
    
            ' The rectangle where to draw the border.
            Dim borderRect As Rectangle = e.ClipRectangle
            With borderRect
                .Y = .Y + (textSize.Height \ 2)
                .Height = .Height - (textSize.Height \ 2)
            End With
    
            ' The rectangle where to draw the header text.
            Dim textRect As Rectangle = e.ClipRectangle
            With textRect
                .X = .X + textOffset
                .Width = (textSize.Width - blankWidthSpace)
                .Height = textSize.Height
            End With
    
            ' Draw the border.
            ControlPaint.DrawBorder(e.Graphics, borderRect, Me.borderColor1, Me.borderStyle1)
    
            ' Fill the text rectangle.
            e.Graphics.FillRectangle(New SolidBrush(Me.BackColor), textRect)
    
            ' Draw the text on the text rectangle.
            textRect.Width = textSize.Width + (blankWidthSpace * 2) ' Fix the right side space.
            e.Graphics.DrawString(Me.Text, Me.Font, New SolidBrush(Me.ForeColor), textRect)
    
        End Sub
    
    #End Region
    
    End Class
    
    #End Region
    
    0 讨论(0)
  • 2021-01-21 23:30

    You can catch the WM_PAINT or WM_ERASEBKGND message and draw the border manually:

    [DllImport("user32.dll")]
    static extern IntPtr GetWindowDC(IntPtr hWnd);
    
    [DllImport("user32.dll")]
    static extern int ReleaseDC(IntPtr hwnd, IntPtr hDC);
    
    protected override void WndProc(ref Message m)
    {
        IntPtr hdc;
        if (m.Msg == 0x14) //WM_ERASEBKGND
        {
            hdc = GetWindowDC(m.HWnd);
    
            if (hdc != IntPtr.Zero)
            {
                using (Graphics g = Graphics.FromHdc(hdc))
                {
                    g.DrawRectangle(Pens.Red, 0, 0, this.Width-1, this.Height-1);
                }
                ReleaseDC(m.HWnd, hdc);
            }
    
        base.WndProc(ref m);
    }
    

    It does have however a problem when the textbox looses it's focus.

    0 讨论(0)
提交回复
热议问题