Setting a ProgressBar Control’s Foreground and Background Colors

The .NET Framework does not provide a way to set foreground color and background color of a progressbar control. This can be done using P/Invoke calls. The default color of the progressbar’s foreground or background is represented as CLR_DEFAULT. It’s not supported to deal with this value directly in .NET, so we use Color.Transparent instead to store this value. To make usage of the class more intuitive, assigning the value of its DefaultColor property to its color properties resets the property value to the default color.

The reason why we do not simply inherit from ProgressBar is that ProgressBar is a NotInheritable class.

When instantiating the class, a progressbar object must be passed to the constructor. In the constructor, the control’s foreground and background values will be reset to their default values. This is necessary to make the properties return correct values:

Public Class ProgressBarHelper
    Private Declare Auto Function SendMessage Lib "user32.dll" ( _
        ByVal hWnd As IntPtr, _
        ByVal wMsg As Int32, _
        ByVal wParam As IntPtr, _
        ByVal lParam As IntPtr _
    ) As IntPtr

    Private Const WM_USER As Int32 = &H400

    Private Const CCM_FIRST As Int32 = &H2000
    Private Const CCM_SETBKCOLOR As Int32 = CCM_FIRST + &H1

    Private Const PBM_SETBARCOLOR As Int32 = WM_USER + 9
    Private Const PBM_SETBKCOLOR As Int32 = CCM_SETBKCOLOR

    Private Const CLR_DEFAULT As Int32 = &HFF000000

    Private m_ProgressBar As ProgressBar
    Private m_BackColor As Color
    Private m_ForeColor As Color
    Private m_OldBackColor As Color
    Private m_OldForeColor As Color

    Public Sub New(ByVal ProgressBar As ProgressBar)
        If ProgressBar Is Nothing Then
            Throw New NullReferenceException()
        End If
        m_ProgressBar = ProgressBar

        ' Reset colors to make calls to property gets for 'ForeColor' and
        ' 'BackColor' return the right value.
        Me.ForeColor = DefaultColor
        Me.BackColor = DefaultColor
    End Sub

    Public ReadOnly Property ProgressBar() As ProgressBar
        Get
            Return m_ProgressBar
        End Get
    End Property

    Public Property ForeColor() As Color
        Get
            Return m_ForeColor
        End Get
        Set(ByVal Value As Color)
            m_ForeColor = Value
            SetBarColor(Me.ForeColor)
        End Set
    End Property

    Public Property BackColor() As Color
        Get
            Return m_BackColor
        End Get
        Set(ByVal Value As Color)
            m_BackColor = Value
            SetBkColor(Me.BackColor)
        End Set
    End Property

    Public Shared ReadOnly Property DefaultColor() As Color
        Get
            Return Color.Transparent
        End Get
    End Property

    Private Function SetBarColor(ByVal Color As Color) As Color
        Return _
            ProgressBarColorToDotNetColor( _
                SendMessage( _
                    m_ProgressBar.Handle, _
                    PBM_SETBARCOLOR, _
                    IntPtr.Zero, _
                    New IntPtr(DotNetColorToProgressBarColor(Color)) _
                ).ToInt32() _
            )
    End Function

    Private Function SetBkColor(ByVal Color As Color) As Color
        Return _
            ProgressBarColorToDotNetColor( _
                SendMessage( _
                    m_ProgressBar.Handle, _
                    PBM_SETBKCOLOR, _
                    IntPtr.Zero, _
                    New IntPtr(DotNetColorToProgressBarColor(Color)) _
                ).ToInt32() _
            )
    End Function

    Private Function DotNetColorToProgressBarColor( _
        ByVal Color As Color _
    ) As Int32
        If Color = DefaultColor Then
            Return CLR_DEFAULT
        Else
            Return ColorTranslator.ToWin32(Color)
        End If
    End Function

    Private Function ProgressBarColorToDotNetColor( _
        ByVal Color As Int32 _
    ) As Color
        If Color = CLR_DEFAULT Then
            Return DefaultColor
        Else
            Return ColorTranslator.FromWin32(Color)
        End If
    End Function
End Class

Usage:

Dim p As New ProgressBarHelper(Me.ProgressBar1)
p.ForeColor = Color.Red
p.BackColor = Color.Blue