Click here to Skip to main content
Click here to Skip to main content

ReadOnly ComboBox

By , 23 Oct 2008
 

Sample.JPG

Introduction

I decided to create a new combobox based on requests from the users of MSDN Windows Forms forum. It adds a new property to the regular ComboBox so it can be set to read-only, much like the regular TextBoxes.

Using the code

I made this code pretty straightforward so all you have to do is download the C# file enclosed in the ZIP file above and add it to your project. Build it, and the ExComboBox should be available on the Toolbox.

You can change the way the disabled button looks by commenting the ComboBoxRenderer line and uncommenting the commented portion of the code. You can set the color of the gradient that makes the button of the read-only mode by changing the colors of the LinearGradientBrush variable lgb on the OnPaint method:

protected class DblPanel : Panel
{
    protected override void OnPaint(PaintEventArgs e)
    {
        if (this.Visible == true)
        {
            ComboBoxRenderer.DrawDropDownButton(e.Graphics, e.ClipRectangle, 
              System.Windows.Forms.VisualStyles.ComboBoxState.Disabled);
            /*Pen pen = new Pen(Color.DarkGray);
            Pen penBR = new Pen(Color.LightGray);
            Pen penArrow = new Pen(Color.LightGray);
            penArrow.Width = 2;
            penArrow.EndCap = LineCap.Square;
            Graphics g = e.Graphics;
            LinearGradientBrush lgb = new LinearGradientBrush(new Point(0, 0), 
                                      new Point(0, this.Height + 1), 
                                      Color.LightGray, Color.Gray);

Points of interest

I learned a bit while trying to add the read-only feature to the regular ComboBox. It is interesting that the combobox does not have any sub-controls in it (check the ComboBox.Controls.Count property and you will see it is 0); all is done by custom drawing. And, I also learned that there is no way to change this by overriding its Paint methods as it doesn't happen there; and, I couldn't figure out where it draws itself, so I used a Panel to draw over the regular dropdown button.

So basically, all the functionality is kept from the original combo box except the ability for the user to change the selected item without disabling the control (many complained that setting the Enabled property to false made it difficult to read and didn't allow the use of custom colors).

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Fabio Franco
Brazil Brazil
Member
Fábio is a party boy that for some reason fell into the geek world. Perhaps his taste for coding came as a consequence of his taste for games, his first program was a batch file for MS-DOS at the age of 14. The need to make it easier to start the games had him do a games menu, with password to blackmail his younger brothers.
 
After that his taste for programming only grew, at the age of 16 Fábio accidentaly stumbled in a program that makes programs, a.k.a. Visual Basic 5.
From there he self taught, through books, how to code in VB 5, 6 and later C, C++ and finally C#.
 
Currently Fábio specializes in C# Desktop and Web Development, that he's been working with since 2004. When he has time, he helps users on MSDN forums and tries to write articles on codeproject.
 
MSDN Profile: http://social.msdn.microsoft.com/profile/f%C3%A1bio%20franco/?type=forum

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Layout  Per page   
GeneralError when Visual Styles not activememberFrazer J10 Dec '09 - 8:29 
Gidday, I have been using this for a while now but the current project I am working on a lot of the PC's do not have visual styles activated. I can't change this. I added the following code (below the error), however I occasionally get this error:
 
Exception:System.ArgumentException: Parameter is not valid.
at System.Drawing.Bitmap..ctor(Int32 width, Int32 height, PixelFormat format)
at System.Drawing.Bitmap..ctor(Int32 width, Int32 height)
at System.Windows.Forms.ControlPaint.DrawFrameControl(Graphics graphics, Int32 x, Int32 y, Int32 width, Int32 height, Int32 kind, Int32 state, Color foreColor, Color backColor)
at System.Windows.Forms.ControlPaint.DrawComboButton(Graphics graphics, Int32 x, Int32 y, Int32 width, Int32 height, ButtonState state)
at System.Windows.Forms.ControlPaint.DrawComboButton(Graphics graphics, Rectangle rectangle, ButtonState state)
 

Protected Class DblPanel
Inherits Panel
Protected Overloads Overrides Sub OnPaint(ByVal e As PaintEventArgs)
If Me.Visible = True Then
If ComboBoxRenderer.IsSupported Then
ComboBoxRenderer.DrawDropDownButton(e.Graphics, e.ClipRectangle, System.Windows.Forms.VisualStyles.ComboBoxState.Disabled)
Else
If Me.Enabled Then
ControlPaint.DrawComboButton(e.Graphics, e.ClipRectangle, ButtonState.Normal)
Else
ControlPaint.DrawComboButton(e.Graphics, e.ClipRectangle, ButtonState.Inactive)
End If
End If
End If
End Sub
End Class
 
Any ideas on how to prevent the error?
GeneralRe: Error when Visual Styles not activememberFabio Franco11 Dec '09 - 2:13 
You say occasionally you get the error? What kind of situation triggers it?
 
What I can notice from your code is that this part is unecessary (unless you changed some more of the behaviour):
 
Else
If Me.Enabled Then
ControlPaint.DrawComboButton(e.Graphics, e.ClipRectangle, ButtonState.Normal)
Else
ControlPaint.DrawComboButton(e.Graphics, e.ClipRectangle, ButtonState.Inactive)
End If
 
You only need to draw if Visible = True. If it's not, then no draw is needed, as the ButtonState.Normal is already drawn by the original control itself as the panel will not be visible.
 
What you want is Check if the ComboBoxRender.IsSupported. If it is, use the VisualStyles, if its not, use the ButtonSatate.Inactive.
 
In any case, ControlPaint's Draw method is causing problems, and I don't know what could be the cause as I'm not familiar with its implementation. To solve the problem I'd recommend you use custom drawing for when the visual styles are disabled, as explained in the article.
 
I'm sorry if I can't help you further.
Regards,
Fábio
GeneralThankyoumemberger0nim016 Jun '09 - 7:23 
Exactly what I'd been looking for. Big thank you.
GeneralRe: ThankyoumemberFabio Franco16 Jun '09 - 7:28 
I'm glad to be of help.
Thanks for your vote.
 
Regards,
Fábio
Questionuse of panel [modified]memberMember 197457029 Apr '09 - 20:21 
Hi
 
You added a panel to your ComboBox control, what r u trying to do there?
r u using the panel to "mask" the control in order to support "ReadOnly"? Correct me if I am wrong.
 

TIA
 
modified on Thursday, April 30, 2009 7:51 AM

AnswerRe: use of panelmemberFabio Franco30 Apr '09 - 1:55 
Hi, I inserted a panel in the inherited control, so it will be on top of the original DropDown button.
The size of the panel is just big enough to cover the whole DropDown button.
Then I draw on this panel to look like a disabled DropDown Button.
 
I hope this answers your question.
Regards,
Fábio
QuestionRe: use of panelmemberMember 197457030 Apr '09 - 2:22 
Thanks Fabio for your reply.
 
So the trick is with the "OnKeyPress" and "OnKeyDown" methods?
 
TIA
AnswerRe: use of panelmemberFabio Franco30 Apr '09 - 5:14 
That too.
 
But there are events that "OnKeyPress" and "OnKeyDown" won't handle.
MouseWheel for example. the MouseWheel also changes the selected item, so to handle it. I need to override the WndProc method, that catches all messages sent to the control, I check if it is a mousewheel message and handle it if it is.
 
There are also the Tab and Arrow keys, that I handle overriding the ProcessCmdKey method.
 
Regards,
Fábio
GeneralSimply usefulmemberGio Bejarasco23 Oct '08 - 9:44 
Nice article Fabio. As someone who is very meticulous on data presentation and validation in winforms, this control is valuable to me. I really wanted to create something like this before but I just couldn't get myself started. I would always resort to the cumbersome combobox-textbox swapping technique.
GeneralRe: Simply usefulmemberDotDue23 Oct '08 - 21:33 
Oh that approach has alway irked me something fierce. I was thrilled to see that someone actually had done it right with this article.
 
--
Thomas Due
"Insanity in individuals is something rare - but in groups, parties, nations and epochs, it is the rule."
-- Friedrich Nietzsche

GeneralRe: Simply usefulmemberFabio Franco24 Oct '08 - 1:05 
Gio Bejarasco wrote:
Nice article Fabio. As someone who is very meticulous on data presentation and validation in winforms, this control is valuable to me. I really wanted to create something like this before but I just couldn't get myself started. I would always resort to the cumbersome combobox-textbox swapping technique.

 
Hi Gio, I'm glad it worked for you. I'm too very meticulous on data presentation and validation and I mean it and this just didn't work for the guys who asked for this, it worked for me as well.
 
Thanks for your feedback.
Regards,
 
Fábio
GeneralA couple of suggestionsmemberDotDue22 Oct '08 - 22:01 
First of, I'd like to say that it is the greatest and simplest solution I have come across yet in my search for a ReadOnly ComboBox.
 
Kudos to you.
 
I have a couple of suggestions for (I think) improvement:
 
1. Make the background grey when ReadOnly, like a TextBox. I do this by adding a line to the setter for ReadOnly:
this.BackColor = (m_Unselectable) ? SystemColors.Control : SystemColors.Window;
 
2. Replace all that code in the Paint for your DblPanel with this:
 

  
protected override void OnPaint(PaintEventArgs e)
{
    if (this.Visible == true)
    {
        ComboBoxRenderer.DrawDropDownButton(e.Graphics, e.ClipRectangle,
            System.Windows.Forms.VisualStyles.ComboBoxState.Disabled);
    }
}
 

But these are only suggestions. The control is still great, and I will definitely be using this in my projects. Cool | :cool:
 
--
Thomas Due
"Insanity in individuals is something rare - but in groups, parties, nations and epochs, it is the rule."
-- Friedrich Nietzsche

GeneralRe: A couple of suggestionsmemberFabio Franco23 Oct '08 - 0:55 
Hi DotDue, I'm glad you found it useful and I appreciate your feedback.
As for your suggestions:
 
DotDue wrote:
1. Make the background grey when ReadOnly, like a TextBox. I do this by adding a line to the setter for ReadOnly:
 

this.BackColor = (m_Unselectable) ? SystemColors.Control : SystemColors.Window;
 


 
I actually prefer not to limit the user to the colors that are set, I leave it to the user so he can do as he pleases. It is easier for someone that would like this feature to do it manually when he handles the EnabledChanged event than the other way around.
And I think this approach would also involve remembering the last back color set, as the way it is now, when the user changes back from ReadOnly state, the back color he had before would be lost.
 

DotDue wrote:
2. Replace all that code in the Paint for your DblPanel with this:
 


protected override void OnPaint(PaintEventArgs e)
{
if (this.Visible == true)
{
ComboBoxRenderer.DrawDropDownButton(e.Graphics, e.ClipRectangle,
System.Windows.Forms.VisualStyles.ComboBoxState.Disabled);
}
}

 
Indeed a much better approach than the one I provided, I will make the changes and update the article. I will leave the older paint code commented, in case someone wishes to give the dropdown button a different color.
 
Thanks again for your feedback.
 
Regards,
Fábio
GeneralRe: A couple of suggestionsmemberDotDue23 Oct '08 - 21:31 
Fabio Franco wrote:
I actually prefer not to limit the user to the colors that are set, I leave it to the user so he can do as he pleases. It is easier for someone that would like this feature to do it manually when he handles the EnabledChanged event than the other way around.
And I think this approach would also involve remembering the last back color set, as the way it is now, when the user changes back from ReadOnly state, the back color he had before would be lost.

 
Oh that is of course true. It is a matter of taste of course. I hadn't thought about the changed background color. It would have to be stored somewhere of course.
 
--
Thomas Due
"Insanity in individuals is something rare - but in groups, parties, nations and epochs, it is the rule."
-- Friedrich Nietzsche

Generalgoodmemberjosephlawrencecarpio29 Jul '08 - 16:53 
you don't appreciate this but in reality, this helps us guys, setting a combobox's property enabled is hard to read. with this, article, it's up to you how you can handle a read-only combo box. Simple as it is.... Smile | :)
 
You've got 5
 
darkmaster35

GeneralRe: goodmemberFabio Franco30 Jul '08 - 4:09 
Thank you Joseph, it is always good to hear that I could be of help to someone.
I did this because I heard from several developers about this reading problem on disabled comboBoxes.
 
Thanks again for your feedback.
Regards,
 
Fábio
GeneralI might be stupidmemberJohnny J.29 Jan '08 - 5:41 
But on your screenshot above, the control shows a gray backcolor when set to readonly. If I try to use your control, the backcolor is white...?!?!?
 
Plus - even if you can't select a new item from the drop down, you can still highlight the text and delete it or change it if the style is dropdown. So it appears that it is not truly readonly... Smile | :)
 
Cheers,
Johnny J.
GeneralRe: I might be stupidmemberFabio Franco29 Jan '08 - 6:14 
Hi, the gray backcolor in this case it is because it is selected and that is the selection color configured in my Test app. About the being able to highlight and delete the text I will check it here.
Thanks for the feedback.
 
Regards,
Fábio
GeneralRe: I might be stupidmemberFabio Franco29 Jan '08 - 7:05 
Ok, I think I let that pass by unoticed. But now you are not able to edit the text when ReadOnly is set to true. Updated link on the top of the page.
 
Regards,
Fábio
GeneralUsing propertymemberdfjohn0053 Jan '08 - 23:56 
Why not just using DropDownStyle property to DropDownList value ???
GeneralRe: Using propertymemberFabio Franco4 Jan '08 - 0:03 
Using the dropdownstyle as dropdownlist won't prevent the user from changing the selected index of the combobox. Perhaps you misunderstood the ReadOnly concept for the ComboBox.
GeneralRe: Using propertymemberThomas Stockwell22 Jan '08 - 8:33 
The you can just set the Enabled property to false.
 
Regards,
Thomas Stockwell
 
Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning.
 
Visit my homepage Oracle Studios[^]

GeneralRe: Using property [modified]memberFabio Franco24 Jan '08 - 3:16 
That is exactly why I made this feature, disabling the combobox makes the text in it hard to read and many complained about that, also with this ReadOnly feature you are also able to select the text, customize the colors and more... Things you can't do while it is disabled.
You should understand the purpose of this article as stated in its introduction.
 
Regards,
Fábio
 
modified on Tuesday, December 9, 2008 6:25 AM

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130516.1 | Last Updated 23 Oct 2008
Article Copyright 2007 by Fabio Franco
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid