8

I am trying to manage the color of the ComboBox. While it is possible to change the background color, I cannot find a property for the border outline.

Just drawing a square as border wont do in a dark theme because of the arrow. This leads me to the conclusion that this border might be an actual image file.

Is it possible to replace this?

enter image description here

UPDATE: I have implemented the Solution of @AhmedAbdelhameed - It looks a lot better now. However for the flat style, I had to adjust the rectangle like the following:

using (var p = new Pen(this.BorderColor, 1))
{
    g.DrawRectangle(p, 0, 0, Width - buttonWidth - 1, Height - 1);
}

I also exchanged the 'BorderColor' to match the rest of my UI:

public CustomComboBox()
{
    BorderColor = Color.Gray;
} 

This is the result so far: enter image description here enter image description here

What I would like to be able to do now is to change the actual drop down button (maybe with an overlay png) only in dark theme

UPDATE: I have been able to add a pricturebox to the custom Control with the following code:

using (var g = Graphics.FromHwnd(Handle))
{
    using (var p = new Pen(this.BorderColor, 1))
    {
        g.DrawRectangle(p, 0, 0, Width - buttonWidth - 1, Height - 1);
    }
    if (Properties.Settings.Default.Theme == "Dark")
    {
        g.DrawImageUnscaled(Properties.Resources.dropdown, new Point(Width - buttonWidth - 1));
    }
}

it looks awesome! more or less by coincidence which I do not understand, the dark dropdown button even disappears, when I change the theme in the theme combobox.

Before - After Comparisation: enter image description here enter image description here

julian bechtold
  • 1,875
  • 2
  • 19
  • 49

2 Answers2

7

With the help of this answer, I was able to come up with the following:

First, add the following into your form to avoid flickering:

protected override CreateParams CreateParams
{
    get
    {
        CreateParams handleParam = base.CreateParams;
        handleParam.ExStyle |= 0x02000000;      // WS_EX_COMPOSITED
        return handleParam;
    }
}

Now, add the following class to your project:

public class CustomComboBox : ComboBox
{
    private const int WM_PAINT = 0xF;
    private int buttonWidth = SystemInformation.HorizontalScrollBarArrowWidth;
    protected override void WndProc(ref Message m)
    {
        base.WndProc(ref m);
        if (m.Msg == WM_PAINT)
        {
            using (var g = Graphics.FromHwnd(Handle))
            {
                // Uncomment this if you don't want the "highlight border".
                /*
                using (var p = new Pen(this.BorderColor, 1))
                {
                    g.DrawRectangle(p, 0, 0, Width - 1, Height - 1);
                }*/
                using (var p = new Pen(this.BorderColor, 2))
                {
                    g.DrawRectangle(p, 2, 2, Width - buttonWidth - 4, Height - 4);
                }
            }
        }
    }

    public CustomComboBox()
    {
        BorderColor = Color.DimGray;
    }

    [Browsable(true)]
    [Category("Appearance")]
    [DefaultValue(typeof(Color), "DimGray")]
    public Color BorderColor { get; set; }
}

Rebuild the project, replace the ComboBox controls with the new CustomComboBox, set the BorderColor property to a color of your choice, and you're good to go.

Result:

ComboBox_BorderColor

Update:

Using the following values seems to give a better result (specially when clicking the dropdown button), but you'll still probably need to draw the first rectangle (the one commented above) to avoid showing the "highlight border" around the button only:

using (var p = new Pen(this.BorderColor, 3))
{
    g.DrawRectangle(p, 1, 1, Width - buttonWidth - 3, Height - 3);
}
  • 1
    I think I have to thank you for linking that ugly a?? of an answer I posted a while ago. I've updated it (for what is possible, at least it doesn't leak anymore). I've made a class out of that Reza Aghaei's answer myself. [This is a PasteBin](https://pastebin.com/CycVmSjK) I had posted (for another site) with the relevant parts. I think there's one thing that needs to be added (when implementing this): `SetStyle(ControlStyles.ResizeRedraw, true)` in the constructor. IIRC, it helps. – Jimi Sep 28 '18 at 00:55
  • 1
    @Jimi Actually, `SetStyle` is what I went with at first but it doesn't seem to get rid of the flicker in this particular case (for some reason!). That's why I replaced it with overriding the `CreateParams` property at the form level, which works for me every time. – 41686d6564 stands w. Palestine Sep 28 '18 at 01:02
  • Yes, sure. I meant, it helps in the form designer, to get the drawing right when resizing the controls (depending on the actual implementation). The flickering is another story; I know that setting `CreateParams` that way is a good workaround in this cases. – Jimi Sep 28 '18 at 01:08
  • Hello Ahmed, thank you for your answer which will already help a lot. Do you think there is also the possibility to get this sqare with a triangle on the right hand side of the Combobox dark? Maybe by overlaying a png? I will implement your solution and update my question then. – julian bechtold Sep 28 '18 at 06:18
  • @julian bechtold If you modify the Control style, with `SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint, true)`, then the `Paint` event will be raised and you can paint anything in the Button area. It'ld take some more work, though. The `WndProc` WM_PAINT override could me moved to the Paint event. All the control's NC area design falls in your hands. – Jimi Sep 28 '18 at 08:55
  • @Jimini, I already updated my question ;) I do it a little "easier" but it works like a charm! – julian bechtold Sep 28 '18 at 08:58
0

To add a border for the full width of the combobox you have to remove the button width from the drawing. In my case, I simply wanted to change the color of the border so 1 pixel was sufficient.

using (var p = new Pen(this.BorderColor, 1))
{
    g.DrawRectangle(p, 0, 0, Width - 1, Height - 1);
}

That meant that the custom combobox behaved exactly like the generic one e.g on hover etc

Nepaluz
  • 669
  • 1
  • 12
  • 27