3

I'm trying to create a custom ComboBox with rounded corners where i'm still able to edit the text through user input. The solution i have so far allows me to have a decent ComboBox but only in DropDownList style, i want to go the extra mile and try to paint the embedded EditControl that appears when the combobox is set to DropDown. The solution i have so far is

Public Sub New()

        ' Esta llamada es exigida por el diseñador.
        InitializeComponent()

        ' Agregue cualquier inicialización después de la llamada a InitializeComponent().
        Me.SetStyle(ControlStyles.UserPaint _
                    Or ControlStyles.AllPaintingInWmPaint _
                    Or ControlStyles.Opaque _
                    Or ControlStyles.ResizeRedraw, True)
        Me.m_ControlBuffer = New Bitmap(Me.Width, Me.Height)
        Me.m_ControlGraphics = Graphics.FromImage(m_ControlBuffer)
        Me.m_BackBuffer = New Bitmap(Me.Width, Me.Height)
        Me.m_BackGraphics = Graphics.FromImage(m_BackBuffer)

        Dim backcolor As Color = If(Enabled, m_UITheme.TextBoxColor, Color.White)
        BackgroundBrush = New SolidBrush(backcolor)
        Me.BackColor = backcolor
    End Sub

and Paint method is

Public Sub CustomPaint(screenGraphics As Graphics)
        ' If there is body to be drawn.
        If Me.Width > 0 AndAlso Me.Height > 0 Then
            ' Clear the background image graphics 
            If Me.m_backImage Is Nothing Then
                '   Cached Background Image
                Me.m_backImage = New Bitmap(Me.Width, Me.Height)
                Dim backGraphics As Graphics = Graphics.FromImage(Me.m_backImage)
                backGraphics.Clear(Color.Transparent)
                Me.PaintTransparentBackground(backGraphics, Me.ClientRectangle)
            End If

            m_BackGraphics.Clear(Color.Transparent)
            m_BackGraphics.DrawImageUnscaled(Me.m_backImage, 0, 0)

            m_ControlGraphics.Clear(Color.Transparent)
            m_ControlGraphics.SmoothingMode = SmoothingMode.HighQuality

            ' Begin drawing
            Dim path As GraphicsPath = GetBoxBorder()
            m_ControlGraphics.FillPath(BackgroundBrush, path)

            PaintArrowAndLine(m_ControlGraphics)

            ' Draw text
            DrawText(m_ControlGraphics)

            m_ControlGraphics.Flush()

            m_BackGraphics.DrawImage(m_ControlBuffer,
                                         New Rectangle(0, 0,
                                                       m_ControlBuffer.Width,
                                                       m_ControlBuffer.Height),
                                         0, 0,
                                         m_ControlBuffer.Width,
                                         m_ControlBuffer.Height,
                                         GraphicsUnit.Pixel)
            m_BackGraphics.Flush()

            '   Now paint this to the screen
            screenGraphics.DrawImageUnscaled(m_BackBuffer, 0, 0)
        End If
    End Sub

The problem is that for DropDown style a white EditControl appears on top of my drawing. Searching on other forums i received the idea of getting a handle of that control and maybe i could change the color. I then found the WM_CTLCOLOREDIT which i think would help me in what i have to do. It says,

If an application processes this message, it must return the handle of a brush. The system uses the brush to paint the background of the edit control.

So what i tried was to catch that message on the WndProc of my ComboBox and alter result of the message (which as i understand is the return value for the WM_CTLCOLOREDIT) to be the pointer to the brush i'm creating.

<DllImport("gdi32.dll")>
Public Shared Function CreateSolidBrush(ByVal color As Integer) As IntPtr
End Function
Protected Overrides Sub WndProc(ByRef m As Message)
    If (m.Msg = &H133) Then
        Dim brush As IntPtr = CreateSolidBrush(RGB(255, 0, 0))
        m.Result = brush
    End If
    MyBase.WndProc(m)

End Sub

I'm not sure how to use the WndProc and this code above still does not work. Any help will be aprecciated.

EDIT: After changing the WndProc,

Private hBrush As IntPtr = CreateSolidBrush(RGB(255, 0, 0))
    Protected Overrides Sub WndProc(ByRef m As Message)

        If (m.Msg = &H133) Then
            m.Result = hBrush
        Else
            MyBase.WndProc(m)
        End If

    End Sub

It does paints the red rectangle except when i have the focus on the control. See Images below, Without focus With focus

I feel so far and so close to the solution at the same time.

  • 1
    If you want to get the handle of the Edit control, use GetComboBoxInfo, as shown [here](https://stackoverflow.com/a/61154093/7444103), for example. Also, see the notes and some comments there: you may find that the .Net Framework version you use can can make a difference. The way the `CB_GETCURSEL` message is handled is just one of the possible differences. – Jimi Jun 05 '20 at 12:34
  • To design a UserControl/Custom Control with smooth rounded region, see here: [How to avoid visual artifacts of colored border of zoomable UserControl with rounded corners?](https://stackoverflow.com/a/54794097/7444103), it may help. This one generates rounded borders (not a Region) in a different way: [Translucent circle with text](https://stackoverflow.com/a/51435842/7444103) – Jimi Jun 05 '20 at 12:43

0 Answers0