7

I want to have an uneditable ComboBox but still show a white background colour, so it is effectively styled like the default ComboBox style (DropDown). The ComboBoxStyle.DropDownList only provides the standard "disabled" looking grey back colour. Simply setting BackColor = Color.White has no effect.

DropDownList: DropDownList

DropDown: DropDown

jordanz
  • 367
  • 4
  • 12
user3424480
  • 362
  • 2
  • 6
  • 19

6 Answers6

9

To make a ComboBox DropDownList look like a ComboBox DropDown:

  1. Add a ComboBox to the WinForm. Go to Properties Explorer. Select DropDownStyle > DropDownList. Then select FlatStyle > Flat.
  2. Add a Panel to the WinForm. Go to Properties Explorer. Select BorderStyle > FixedSingle.
  3. Drag ComboBox onto Panel. With ComboBox active, go to Properties Explorer > Dock > Fill.
  4. With ComboBox active, hold the ‘Shift’ key, select the Panel to make it active as well (order of selection is important).
  5. Go to the Layout Toolbar (View > ToolBars > Layout) and select ‘Make Same Size’.
  6. When you run your program, the DropDownList ComboBox should look like a DropDown ComboBox
Cruzer
  • 91
  • 1
  • 4
3

To achieve a DropDownList combobox with a white background create a simple wrapper class:

  public class ComboBoxClean : ComboBox
    {
        public ComboBoxClean()
        {
            DropDownStyle = ComboBoxStyle.DropDownList;
            DrawMode = DrawMode.OwnerDrawFixed;
        }

        protected override void OnDrawItem(DrawItemEventArgs e)
        {
            Color textColor = e.ForeColor;

            if ((e.State & DrawItemState.Focus) != DrawItemState.Focus)
                e.DrawBackground();
            else
                textColor = Color.Black;

            e.DrawFocusRectangle();

            var index = e.Index;
            if (index < 0 || index >= Items.Count) return;
            var item = Items[index];

            string text = (item == null) ? "(null)" : item.ToString();
            using (var brush = new SolidBrush(textColor))
            {
                e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
                e.Graphics.DrawString(text, e.Font, brush, e.Bounds);
            }
        }
    }
Adam
  • 2,762
  • 1
  • 30
  • 32
  • 1
    This is definitely the best way to go about this, but, as coded, the text color of the highlighted entry is Black (on a blue background), not White as it should be. I'm new to dealing with drawing so I'm trying to figure out how to fix that. – technonaut Nov 12 '20 at 21:51
  • 1
    @technonaut, remove check `if ((e.State & DrawItemState.Focus) != DrawItemState.Focus)` and setting `textColor = Color.Black;`. This worked to me. – Creek Drop Feb 01 '21 at 14:21
2

I played around with this for a while and didn't want to do anything too involved. Those ideas above probably work but all I did was change the flatStyle property from "standard" to "flat".

Although not perfect, it at least changes the background that grey/disabled look to white.

You can see the comparison here:

Heating Source #1 > DropdownList > flat (the final decision since dropdown was allowing users to enter bad data)

Heater Source #2 > Dropdown > Standard (the default which looks nice)

Housing Type > Dropdown > Flat

Heating Source #1 Vendor > DropdownList > Standard (the default which looks disabled greyenter image description here)

blind Skwirl
  • 321
  • 3
  • 6
2

I came across this post seeking a solution to this very problem but couldn't find a solution that was exactly what I needed. I experimented a bit and came up with this solution for Visual Basic .NET that's a blend of Adam's code here on this post and others here.

I'm going to show two different ways of doing this, with some brief discussion of pro's and con's:

  1. Hooking the DrawItem event;
  2. Creating a custom control.

============================ METHOD 1 ===============================

This method simply hooks the ComboBox's DrawItem event, so it doesn't need a custom control.

STEP 1

Add your ComboBox as usual. In its Properties, change DrawMode to OwnerDrawFixed. If you forget this, the next part won't do anything. Of course, also change your DropDownStyle to DropDownList.

STEP 2

Add a custom handler:

Private Sub ComboBox1_DrawItem(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DrawItemEventArgs) Handles ComboBox1.DrawItem
    Dim cmb = CType(sender, ComboBox)
    If cmb Is Nothing Then Return

    Dim index As Integer = If(e.Index >= 0, e.Index, -1)
    Dim brush As Brush = If(((e.State And DrawItemState.Selected) > 0), SystemBrushes.HighlightText, New SolidBrush(cmb.ForeColor))
    e.DrawBackground()

    If index <> -1 Then
        e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit
        e.Graphics.DrawString(cmb.Items(index).ToString(), e.Font, brush, e.Bounds, StringFormat.GenericDefault)
    End If

    e.DrawFocusRectangle()
End Sub

NOTE

You can use a single sub to handle multiple ComboBoxes, but you have to remember to manually add them to the Handles.

============================ METHOD 2 ===============================

This method relies on a custom control that inherits from ComboBox. By adding this custom control to our form, instead of a normal ComboBox, it will just work - we don't have to worry about a Handles statement. If you plan on having several ComboBoxes, this might be the way to go.

STEP 1

Add a custom control by right clicking your project, Add, New Item, and select Custom Control (Windows Forms). I named mine ComboBoxClean.

STEP 2

In file ComboBoxClean.vb, replace the the automatically-generated code with this:

Public Class ComboBoxClean
    Inherits ComboBox

    Public Sub New()
        DropDownStyle = ComboBoxStyle.DropDownList
        DrawMode = DrawMode.OwnerDrawFixed
    End Sub

    Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
        MyBase.OnPaint(e)
    End Sub

    Protected Overrides Sub OnDrawItem(ByVal e As DrawItemEventArgs)
        Dim index As Integer = If(e.Index >= 0, e.Index, -1)
        Dim brush As Brush = If(((e.State And DrawItemState.Selected) > 0), SystemBrushes.HighlightText, New SolidBrush(ForeColor))
        e.DrawBackground()

        If index <> -1 Then
            e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit
            e.Graphics.DrawString(Items(index).ToString(), e.Font, brush, e.Bounds, StringFormat.GenericDefault)
        End If

        e.DrawFocusRectangle()
    End Sub
End Class

STEP 3

In the solution explorer, click Show All Files. Open ComboBoxClean.Designer.vb.

Replace the existing Inherits statement with this one:

Inherits ComboBox

NOTES

  • You should go ahead and Build before you try to use it just to be sure all is well.
  • In the Toolbox, your custom control will not be in the normal control list. Your current solution should have its own Components section there, which is where you should find the new control. Simply drag it onto your form and use it like a normal combobox.
  • The sub New takes care of automatically making important property changes for us, that we'd otherwise have to do manually each time we added a new ComboBox.
technonaut
  • 484
  • 3
  • 12
  • Thanks for this technonaut. I did notice that the font wasn't as smooth and nice looking as the regular controls. I changed the StringFormat to StringFormat.GenericTypographic and it looked exactly the same. – John Williams Jun 22 '23 at 23:58
  • One more comment. I just spent a good while looking at a project whose forms wouldn't load. The project didn't recognize the new combo boxes. I ended up adding InitializeComponent() as the first line in Public Sub New() and everything worked again. – John Williams Jun 23 '23 at 08:04
1

Having struggled trying to get the control looking identical to the DropDown ComboBox style I had to settle with overriding the OnKeyPress event so that it restricted the user from been able to edit the control. As a side note I would also recommend overriding the appropriate event to prevent users pasting values into the ComboBox (how to disable copy, Paste and delete features on a textbox using C#).

protected override void OnKeyPress(KeyPressEventArgs e)
{
    e.Handled = true;
}
Community
  • 1
  • 1
user3424480
  • 362
  • 2
  • 6
  • 19
  • You also have to prevent rightclicks due to being able to cut/paste inside of it and edit it that way – Gaspa79 May 11 '20 at 11:33
0

You will have to create your own ComboBox with custom drawing or use a third-party control such as Infragistics UltraCombo

public class MyComboBox : ComboBox
    {
        public MyComboBox()
        {
            this.SetStyle(ControlStyles.UserPaint, true);
        }

        protected override void OnPaint(PaintEventArgs e)
        {
          // Repaint here
        }
    }
radianz
  • 71
  • 5