65

I do not want the user to be able to change the value displayed in the combobox. I have been using Enabled = false but it grays out the text, so it is not very readable. I want it to behave like a textbox with ReadOnly = true, where the text is displayed normally, but the user can't edit it.

Is there is a way of accomplishing this?

CodesInChaos
  • 106,488
  • 23
  • 218
  • 262
Kishore A
  • 1,293
  • 3
  • 16
  • 21

18 Answers18

175

make DropDownStyle property to DropDownList instead of DropDown then handle the TextChanged event to prevent user changing text.

Nam Bình
  • 412
  • 2
  • 13
23

The article ComboBox-with-read-only-behavior suggests an interesting solution:

Create both a readonly textbox and a combobox in the same place. When you want readonly mode, display the textbox, when you want it to be editable, display the combobox.

CodesInChaos
  • 106,488
  • 23
  • 218
  • 262
  • 4
    Downvoted because: This answer is not realy useful. The standard combobox control already provides the desired functionality as @amar vashi pointed out. – Andreas Mar 09 '18 at 19:42
  • @Andreas - downvote not deserved because this *does* address what the OP wanted; ReadOnly behaviour like the TextBox control, not "limiting user input to items in the list" as most people have assumed. The linked CodeProject article is a more thorough implementation of Niall's answer below. – Rhys Jones May 20 '20 at 21:01
11

Not sure if this is what you're looking for but...

Set the DropDownStyle = DropDownList

Then on the SelectedIndexChanged event

if (ComboBox1.SelectedIndex != 0)
{
    ComboBox1.SelectedIndex = 0;
}

This ugly part is that they will "feel" like they can change it. They might think this is an error unless you give them an alert telling them why they can't change the value.

ashveli
  • 248
  • 6
  • 28
Dan Williams
  • 4,910
  • 11
  • 37
  • 46
9

enter link description here

Just change the DropDownStyle to DropDownList. Or if you want it completely read only you can set Enabled = false, or if you don't like the look of that I sometimes have two controls, one readonly textbox and one combobox and then hide the combo and show the textbox if it should be completely readonly and vice versa.

Virus
  • 167
  • 1
  • 11
9

The best thing I can suggest is to replace the combo-box with a read-only textbox (or just perhaps a label) - that way the user can still select/copy the value, etc.

Of course, another cheeky tactic would be to set the DropDownStyle to DropDownList, and just remove all other options - then the user has nothing else to pick ;-p

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
5

I've handled it by subclassing the ComboBox to add a ReadOnly property that hides itself when set and displays a ReadOnly TextBox on top containing the same Text:

class ComboBoxReadOnly : ComboBox
{
    public ComboBoxReadOnly()
    {
        textBox = new TextBox();
        textBox.ReadOnly = true;
        textBox.Visible = false;
    }

    private TextBox textBox;

    private bool readOnly = false;

    public bool ReadOnly
    {
        get { return readOnly; }
        set
        {
            readOnly = value;

            if (readOnly)
            {
                this.Visible = false;
                textBox.Text = this.Text;
                textBox.Location = this.Location;
                textBox.Size = this.Size;
                textBox.Visible = true;

                if (textBox.Parent == null)
                    this.Parent.Controls.Add(textBox);
            }
            else
            {
                this.Visible = true;
                this.textBox.Visible = false;
            }
        }
    }
}
Niall
  • 1,551
  • 4
  • 23
  • 40
5

Here is the Best solution for the ReadOnly Combo.

private void combo1_KeyPress(object sender, KeyPressEventArgs e)
{
    e.KeyChar = (char)Keys.None;
}

It will discard the keypress for the Combo.

LPL
  • 16,827
  • 6
  • 51
  • 95
Manish Parmar
  • 859
  • 1
  • 11
  • 19
2

Michael R's code works, but...
The DropDownHeight = 1; must be back to the default value when ReadOnly property is set to false. So, insert before base.OnDropDown(e): DropDownHeight = 106;

using System;
using System.Threading;
using System.Windows.Forms;

namespace Test_Application
{
    class ReadOnlyComboBox : ComboBox
    {
        private bool _readOnly;
        private bool isLoading;
        private bool indexChangedFlag;
        private int lastIndex = -1;
        private string lastText = "";

        public ReadOnlyComboBox()
        {
        }

        public bool ReadOnly
        {
            get { return _readOnly; }
            set { _readOnly = value; }
        }

        protected override void OnDropDown (EventArgs e)
        {
            if (_readOnly)
            {
                DropDownHeight = 1;
                var t = new Thread(CloseDropDown);
                t.Start();
                return;
            }
            DropDownHeight = 106; //Insert this line.
            base.OnDropDown(e);
        }

        private delegate void CloseDropDownDelegate();
        private void WaitForDropDown()
        {
            if (InvokeRequired)
            {
                var d = new CloseDropDownDelegate (WaitForDropDown);
                Invoke(d);
            }
            else
            {
                DroppedDown = false;
            }
        }
        private void CloseDropDown()
        {
            WaitForDropDown();
        }

        protected override void OnMouseWheel (MouseEventArgs e)
        {
            if (!_readOnly) 
                base.OnMouseWheel(e);
        }

        protected override void OnKeyDown (KeyEventArgs e)
        {
            if (_readOnly)
            {
                switch (e.KeyCode)
                {
                    case Keys.Back:
                    case Keys.Delete:
                    case Keys.Up:
                    case Keys.Down:
                        e.SuppressKeyPress = true;
                        return;
                }
            }
            base.OnKeyDown(e);
        }

        protected override void OnKeyPress (KeyPressEventArgs e)
        {
            if (_readOnly)
            {
                e.Handled = true;
                return;
            }
            base.OnKeyPress(e);
        }
    }
}

To complete this answer:

File -> New -> Project... Visual C# -> Windows -> Classic Desktop -> Windows Forms Control Library

type the Name of your control - OK and paste this code.

You can choose the name of your dll file:
Project - yourproject Properties...

  • Assembly name: type the name. Just build the solution and you have your dll file. So, open the project where you want to use your Read Only combo, right click on References
  • Add Reference... and browse your dll file. To Insert your custom component into Toolbox, open your Toolbox, right click on General tab -> Choose Items...
  • Browse your dll file - Open. Now you can use your ReadOnlyComboBox in your projects. PS: I'm using VS2015.
Jimi
  • 29,621
  • 8
  • 43
  • 61
Fabio
  • 21
  • 1
1

This is how you would address the fact that a ComboBox with Enabled = False is hard to read:

A combobox that looks decent when it is disabled

Victor Zakharov
  • 25,801
  • 18
  • 85
  • 151
1

Actually, its rather simple:

Private Sub combobox1_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles combobox1.KeyDown
    ' the following makes this the combobox read only    
    e.SuppressKeyPress = True    
End Sub
CodesInChaos
  • 106,488
  • 23
  • 218
  • 262
Rob
  • 3,488
  • 3
  • 32
  • 27
1

You can change the forecolor and backcolor to the system colors for an enabled combo box, although this may confuse the users (why have it if they can't change it), it will look better.

Tom Anderson
  • 10,807
  • 3
  • 46
  • 63
0

Set DropdownStyle Property to Simple

Add below code to to KeyPress event of ComboBox

private void comboBoxName_KeyPress(object sender, KeyPressEventArgs e)
{
    e.Handled = true;
    return;
}

Add below code to to KeyDown event of ComboBox

private void comboBoxName_KeyDown(object sender, KeyEventArgs e)
{
    e.Handled = true;
    return;
}
Nalaka526
  • 11,278
  • 21
  • 82
  • 116
0

If you've already populated it, and selected the appropriate item, and made it a DropDownList, then you can use an extension method like this to quickly reduce the selection list down to just the selected item:

public static void MakeReadOnly(this ComboBox pComboBox) {
   if (pComboBox.SelectedItem == null)
      return;

   pComboBox.DataSource = new List<object> {
      pComboBox.SelectedItem
   };
}
Dave Cousineau
  • 12,154
  • 8
  • 64
  • 80
0

I know that I'm a little late to the party, but I was researching this exact question and I knew that there had to be some way to make the combobox readonly as if it were a textbox and disabled the list popping up. It's not perfect, but it is definitely better than all of the answers I've been finding all over the internet that don't work for me. After the button is pressed and the OnDropDown is called, a new thread is created that will set the DroppedDown property to false, thus creating the effect of "nothing happening." The mouse wheel is consumed and key events are consumed as well.

using System;
using System.Threading;
using System.Windows.Forms;

namespace Test_Application
{
    class ReadOnlyComboBox : ComboBox
    {
        private bool _readOnly;
        private bool isLoading;
        private bool indexChangedFlag;
        private int lastIndex = -1;
        private string lastText = "";

        public ReadOnlyComboBox()
        {
        }

        public bool ReadOnly
        {
            get { return _readOnly; }
            set { _readOnly = value; }
        }

        protected override void OnDropDown(EventArgs e)
        {
            if (_readOnly)
            {
                DropDownHeight = 1;
                var t = new Thread(CloseDropDown);
                t.Start();
                return;
            }
            base.OnDropDown(e);
        }

        private delegate void CloseDropDownDelegate();
        private void WaitForDropDown()
        {
            if (InvokeRequired)
            {
                var d = new CloseDropDownDelegate(WaitForDropDown);
                Invoke(d);
            }
            else
            {
                DroppedDown = false;
            }
        }
        private void CloseDropDown()
        {
            WaitForDropDown();
        }

        protected override void OnMouseWheel(MouseEventArgs e)
        {
            if (!_readOnly) 
                base.OnMouseWheel(e);
        }

        protected override void OnKeyDown(KeyEventArgs e)
        {
            if (_readOnly)
            {
                switch (e.KeyCode)
                {
                    case Keys.Back:
                    case Keys.Delete:
                    case Keys.Up:
                    case Keys.Down:
                        e.SuppressKeyPress = true;
                        return;
                }
            }
            base.OnKeyDown(e);
        }

        protected override void OnKeyPress(KeyPressEventArgs e)
        {
            if (_readOnly)
            {
                e.Handled = true;
                return;
            }
            base.OnKeyPress(e);
        }
    }
}
0

Simplest way in code:

instead of adding methods for KeyPress or KeyDown, add this code on 'Form1_Load' method:

comboBox1.KeyPress += (sndr, eva) => eva.Handled = true;

or

comboBox1.KeyDown += (sndr, eva) => eva.SuppressKeyPress = true;

(sndr, eva) is for (object sender, EventArgs e)

snir
  • 2,961
  • 1
  • 17
  • 10
0

Why don't you just use a text box? Text box has a "Read only" property, and since you want your combo box only to display data, I don't see why you would need a combo box.

An alternative is that you just cancel out the input for the "on value changed" event. That way you will be displaying your information no mater what user does ...

David Božjak
  • 16,887
  • 18
  • 67
  • 98
0

I dont know if that is what you are looking but this prevents the user from chosing any item from the drop down and still be able to type text in the combobox. If you dont want the user to type text in the combobox you can make it Dropdown list from the properties menu.

So you get Read Only combobox.

  1. On Selected Index Changed
  2. Make the selected Index -1 "comboBox.SelectedIndex = -1";

        private void MyComboBox_comboBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            MyComboBox_comboBox.SelectedIndex = -1; 
    
        }
    
Stefan27
  • 845
  • 8
  • 19
-1

Here is the Best solution for the ReadOnly Combo.

private void combo1_KeyPress(object sender, KeyPressEventArgs e) {
    e.KeyChar = (char)Keys.None; 
} 

It will discard the keypress for the Combo. It doesn't have "e.KeyChar" !

NullUserException
  • 83,810
  • 28
  • 209
  • 234
Behzad
  • 1,740
  • 1
  • 22
  • 49