Change (custom) ProgressBar color

2019-02-20 04:15发布

问题:

I'm creating a custom progress bar with a property

Public Class CustomProgressBar : Inherits ProgressBar

    Private _State As ProgressStates

    <DllImport("user32.dll", CharSet:=CharSet.Auto)> _
    Private Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal msg As Integer, ByVal wParam As Integer, <MarshalAs(UnmanagedType.LPWStr)> ByVal lParam As String) As Int32
    End Function

    <Category("Appearance")> _
    <DefaultValue(ProgressStates.Normal)> _
    <Description("The progress state, Red=Error, Yellow=Warning, Green=Normal")> _
    Public Property State As ProgressStates
        Get
            Return _State
        End Get
        Set(value As ProgressStates)
            _State = value
            SendMessage(MyBase.Handle, 1040, value, 0)
        End Set
    End Property

End Class

ProgressStates

Public Enum ProgressStates

    Normal = 1
    [Error] = 2
    Warning = 3

End Enum

In the designer I set my custom property to Error and it works fine (in the designer), but when I run my application, progress value sets automatically to 0 and property is not applied

回答1:

It has nothing to do with the Property exactly, but the PInvoke is imperfect either in the source or your conversion. I suspect you started with this old C# answer.

Imports System.Runtime.InteropServices
Class NativeMethods
    <DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=False)>
    Private Shared Function SendMessage(hWnd As IntPtr,
                                        Msg As UInt32,
                                        w As IntPtr,
                                        l As IntPtr) As IntPtr
    End Function

    Private Const PBM_SETSTATE = &H400 + 16
    Friend Enum PBMStates
        Normal = 1
        [Error] = 2
        Paused = 3
    End Enum

    Friend Shared Sub SetProgressState(ctl As ProgressBar, state As PBMStates)
        SendMessage(ctl.Handle, PBM_SETSTATE, New IntPtr(state), IntPtr.Zero)
    End Sub
End Class

According to the MSDN docs, PBM_SETSTATE returns the previous state. I've ignored that and made it a Sub. Since it only is supposed to be used with a ProgressBar I it to accept only a ProgressBar control rather than a control handle (which could be from any control). Finally, the code is Shared and in a NativeMethods class so CA will not complain. Usage:

NativeMethods.SetProgressState(ProgressBar1, NativeMethods.PBMStates.Error)

Result: