Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

ComboBox with Read Only Behavior

0.00/5 (No votes)
25 Apr 2005 3  
An article about developing a ComboBox with the same read only functionality as the TextBox

Contents

Introduction

ReadReadOnly Behavior of the TextBox

TextBox controls have the nice read only feature. When you set the ReadOnly property of a TextBox to true, you can't edit the text in the TextBox anymore. The user can still select the text and copy it to another place. The background of the TextBox is painted gray so the user has a visual indication of the ReadOnly mode. The text is still painted in black, as in a normal editable TextBox.

This behavior is completely different to Enabled = false. Via the Enabled property, you can completely disable the TextBox. The text is not painted in good readable black anymore but in a gray color. And you can't select the text anymore.

Read only mode of TextBox

The ReadOnly mode is very usable. I often use it, when I have a form with several controls where the user can edit the content of controls depending on his privileges. If the user doesn't have the required privileges, I do not disable the controls but set them to ReadOnly. This way, the user can still very well read the texts in the TextBoxes, because their text is still painted in black.

No ReadOnly property for ComboBoxes

Most other .NET controls don't have a ReadOnly property. So if you want them to be read only, you have to disable them (Enabled = false). What I wanted was a ComboBox that offers a ReadOnly property and mimics the read only behavior of the TextBox. Especially, paint the text in good readable black instead of the disabled color gray.

DropDown Styles

Several people on the net argue, you don't need a ReadOnlyComboBox, because a ComboBox is read only when you set the DropDownStyle of the ComboBox to DropDownList. Well, of course, doing this, the user cannot edit the text in the ComboBox anymore. But he can still select a value from the ComboBox. For me, that's not the same thing as ReadOnly.

Solution

Idea

I tried different things like hooking into the WndProc to capture all the keyboard and mouse events and handle them myself, if the ComboBox is ReadOnly. But it just did not work out. I'm sure I did something wrong, but anyway. I'd also had to do the painting myself, where I had some problems as well.

Finally, I came up with a completely different idea. Whenever the ComboBox is set to ReadOnly = true, I display a TextBox instead that is read only. Because when it's read only, I don't need the dropdown button at all so a TextBox fits everything needed here.

Read only mode of ComboBox

Implementation

Basics

I found two implementation possibilities:

User Control Decorating the ComboBox and the TextBox

I could have created a new user control having a ComboBox and a TextBox at the same position. The user control acts as a decorator to the two embedded controls, and depending on the ReadOnly property, acts as a TextBox or a ComboBox.

I decided not to do that. Why should I do all the work to decorate the ComboBox? So I came up with solution two.

Inherit from ComboBox and Just Decorate the TextBox

I create a new control (ReadOnlyComboBox) that inherits from the standard ComboBox control and contains a TextBox. Whenever the ReadOnlyComboBox is set to read only, it acts as a decorator for the embedded TextBox and displays the TextBox instead of the ComboBox.

ReadOnly

First, I added a new property ReadOnly that handles the read only state.

public bool ReadOnly
{
  get { return _isReadOnly; }
  set
  {
    if (value != _isReadOnly)
    { 
      _isReadOnly = value;

      ShowControl();
    }
  }
}

The ShowControl() method is responsible to show either the ComboBox or the TextBox depending on the ReadOnly and the Enabled properties.

private void ShowControl()
{
  if (_isReadOnly)
  {
    _textbox.Visible = _visible && this.Enabled;
    base.Visible = _visible && !this.Enabled;
    _textbox.Text = this.Text;
  }
  else
  {
    _textbox.Visible = false;
    base.Visible = _visible;
  }
}

Visible

The ComboBox already has a Visible property. But we have to implement our own Visible property to store the control's visibility. The reason is simple: when we use the ReadOnly property, we change the visibility of the ComboBox. Thus the Visible property of the ComboBox does not correspond to the visibility of the ReadOnlyComboBox. That's why I declare a new Visible property that hides the original Visible property of the ComboBox.

public new bool Visible
{
  get { return _visible; }
  set
  {
    _visible = value;
    ShowControl();
  }
}

But just replacing the Visible property is not enough. The two methods Show() and Hide() need to be replaced as well, to use our new Visible property.

public new void Show()
{
  this.Visible = true;
}
  
public new void Hide()
{
  this.Visible = false;
}

Add the TextBox

While we have already used our TextBox, we have not yet created it. We'll do that in the constructor.

public ReadOnlyComboBox()
{
  _textbox = new TextBox();
}

But that's not enough. We have to add the TextBox to the parent container and we have to copy several properties of the ComboBox to the TextBox. To add the TextBox, we override OnParentChanged() of the ComboBox.

protected override void OnParentChanged(EventArgs e)
{
  base.OnParentChanged(e);
   
  if (Parent != null)
    AddTextbox();
  _textbox.Parent = this.Parent;
}
   
private void AddTextbox()
{
  _textbox.ReadOnly = true;
  _textbox.Location = this.Location;
  _textbox.Size = this.Size;
  _textbox.Dock = this.Dock;
  _textbox.Anchor = this.Anchor;
  _textbox.Enabled = this.Enabled;
  _textbox.Visible = this.Visible;
  _textbox.RightToLeft = this.RightToLeft;
  _textbox.Font = this.Font;
  _textbox.Text = this.Text;
  _textbox.TabStop = this.TabStop;
  _textbox.TabIndex = this.TabIndex;
}

Rest

In the AddTextbox() method, we make sure that the TextBox has the same behavior (like size, location, docking, anchor, etc.) like the ComboBox. But what if one of these properties changes during runtime? We have to make sure that such changes are propagated from the ComboBox to the TextBox. Therefore, I override several of the OnXXXX() methods of the ComboBox. Just a few of the overridden methods as example:

protected override void OnSelectedIndexChanged(EventArgs e)
{
  base.OnSelectedIndexChanged(e);
  if (this.SelectedItem == null)
    _textbox.Clear();
  else
    _textbox.Text = this.SelectedItem.ToString();
}
  
protected override void OnEnabledChanged(EventArgs e)
{
  base.OnEnabledChanged(e);
  ShowControl();
}
  
protected override void OnDropDownStyleChanged(EventArgs e)
{
  base.OnDropDownStyleChanged(e);
  _textbox.Text = this.Text;
}
  
protected override void OnResize(EventArgs e)
{
  base.OnResize(e);
  _textbox.Size = this.Size;
}
  
protected override void OnLocationChanged(EventArgs e)
{
  base.OnLocationChanged(e);
  _textbox.Location = this.Location;
}

That's it. We finally have our ReadOnlyComboBox. In the same way, you could do a ReadOnlyDateTimePicker or a ReadOnlyNumericalUpDown and so on.

I will develop more read only enabled controls in the future. You'll find them here. Of course, if I have to implement one of them in a different way, I'll put it to Code Project again.

History

  • 03/28/2005: Initial version
  • 04/21/2005: First update
    • Added: Show() and Hide() methods because the Show() and Hide() methods of the parent ComboBox did not use our new Visible property but the Visible property of the parent control.
    • Bugfix: OnSelectedIndexChanged raised an exception when no item was selected (thanks to Alexandre Cunha for reporting this bug).
    • Bugfix: The TextBox is now added in the OnParentChanged() method. That solves several problems compared to the old solution where it was added in the ReadOnly property (thanks again to Alexandre Cunha for reporting one of these problems).
    • Changed: When the ComboBox was disabled, it showed a disabled ComboBox as it should be. When it was disabled and at the same time ReadOnly was true, it showed a disabled TextBox. When disabled, it now always shows a disabled ComboBox.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here