2

SCENARIO

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

When I see my application, it looks like this:

enter image description here

But when I use the normal Aero theme, it looks with horrible white borders everywhere:

enter image description here

QUESTION

I know that the color-scheme used in the app depends on the visual style, but:

I can inherit the TextBox, ComboBox, and TabControl to change the drawn border color to use a darker color? How to?

UPDATE

My TextBoxes are using a BorderStyle property value of Fixed3D

My ComboBoxes are using a FlatStyle property with value of Flat, and are set as DropDownList

ElektroStudios
  • 19,105
  • 33
  • 200
  • 417
  • have you tried just specifying the exact colors you want to use on the groupbox outline and the tabcontrol border? see this for info on styling a groupbox http://stackoverflow.com/a/9362557/526704 – DLeh Dec 01 '14 at 14:11
  • That is for WPF, there is any property to set the outline color in winforms, anyways thankyou. – ElektroStudios Dec 01 '14 at 14:12
  • oh sorry about that. there's probably a way to do it in winforms too. see this: https://social.msdn.microsoft.com/Forums/windows/en-US/60767912-6ea4-4ff6-acb5-44002bd94e82/how-to-change-border-color-of-groupbox-in-cnet – DLeh Dec 01 '14 at 14:13
  • @DLeh Thankyou! it works perfect, but I've tried to reproduce the same with a textbox (with 3D borderstyle set as the images above) and it does not write any border, I'm now testing the same with the other controls – ElektroStudios Dec 01 '14 at 14:50
  • With the Button, ComboBox, and TabContorl also I can't find the way to change the border, maybe because a Button has a BorderStyle property and maybe it needs to override the OnPaint with other logic, and ComboBox have a flatStyle so I suppose the same. – ElektroStudios Dec 01 '14 at 14:52
  • I'm silly, Ive found the easy way to customize the button using a FlatStyle and setting the border in the FlatAppearance. But the textbox and the combobox are hard for me... – ElektroStudios Dec 01 '14 at 15:05
  • Directly from MSDN: `Some Windows Forms controls, such as TextBox, are painted directly by Windows. In these instances, the OnPaint method is never called.` then...? – ElektroStudios Dec 01 '14 at 15:14
  • "I'm using a 3rd party windows visual theme." What product is that? – RenniePet Dec 01 '14 at 15:53
  • @RenniePet Well, is not a software product, is a Theme (my own developed visual theme). http://msdn.microsoft.com/en-us/library/windows/desktop/hh270423%28v=vs.85%29.aspx – ElektroStudios Dec 01 '14 at 16:14

2 Answers2

1

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

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
ElektroStudios
  • 19,105
  • 33
  • 200
  • 417