7
votes

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

6
try the IsEditable and IsReadOnly properties msdn.microsoft.com/en-us/library/…Slai
That's for WPF not WinForms, thanks tho.user3424480

6 Answers

9
votes

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
3
votes

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);
            }
        }
    }
2
votes

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)

2
votes

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.
1
votes

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;
}
0
votes

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
        }
    }