Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / WinForms

ColorComboBox

4.58/5 (18 votes)
3 Jul 2008CPOL4 min read 3   3.7K  
A ColorComboBox color picker using ToolStripDropDown.
With Extended Color Set:

ExtendedColors.JPG

With Basic Color Set:

Introduction

This is a demonstration on the use of the ToolStripDropDown class by creating a color picker combobox. Honestly, I'm surprised that the .NET framework doesn't come with this control, as any rich text editor application would need one of these in their toolbar.

Background

As this is my first attempt at C# programming, my first thought for accomplishing the task of creating the ColorComboBox was to create a control that would inherit from a CheckBox, which when checked would create and display a form without a title bar, where the form would house the flat radio buttons representing the colors. While the popup window is being displayed, any mouse clicks outside of it has to be detected in order to close the popup. I soon learned that the only way to pickup the mouse click outside of the popup window is to use a Windows Hook (we all know that capturing the mouse would not allow the user to click on the child buttons). But, that would tie this control to windows. So, I had to find a .NET way of doing the same thing, which led me to the ToolStripDropDown class.

The other problem with this thought process was that I was exposing the checkbox's properties to the outside world. The checkbox needed to be flat, with no autosize, and the Text property had to be empty. The first two, if not set correctly, would have catastrophic results. So, I wrapped the entire thing with a UserControl derived class in order to hide the CheckBox's properties from the user.

There was another hurdle to overcome. When the dropdown was being displayed and the user clicked on the dropdown button to dismiss the dropdown, it would close, and immediately reopen. The only solution that I have found for this problem is to disable the dropdown button while the dropdown is being displayed. That is done with the help of a Timer. It is not the perfect solution, but it is the only one I could come up with.

So, the end result consists of a ColorComboBox (derived from UserControl) which contains a ColorComboButton (derived from CheckBox) which contains a PopupWindow (derived from ToolStripDropDown) which contains a ColorPopup (derived from UserControl) which contains a ColorRadioButton (derived from RadioButton).

Let's get into some detail.

Let's start with the ColorChangedHandler event. The ColorComboBox, PopupWindow, and ColorComboButton all have a ColorChangedHandler. The ones in PopupWindow and ColorComboButton are invisible to the user of the class; they are used internally to pass the color changed event down the chain of commands.

C#
//define the color changed event argument
public class ColorChangeArgs : System.EventArgs
{
   public ColorChangeArgs(Color color)
   {
      this.color = color;
   }

   //the selected color
   public Color color;
}

//event handler delegate
public delegate void ColorChangedHandler(object sender, ColorChangeArgs e);

The ColorComboBox class, which inherits form UserControl, is pretty simple itself. It has a constructor, and two event handlers, one for the SizeChanged event and another to catch the ColorChanged event form the color popup, to relay to the parent control.

C#
public partial class ColorComboBox : UserControl
{
   /// <summary>
   /// Set or get the selected color
   /// </summary>
   public Color SelectedColor
   {
      get
      {
         return button.SelectedColor;
      }
      set
      {
         button.SelectedColor = value;
      }
   }

   

   /// <summary>
   /// Set whether the control is in extended color mode or normal mode
   /// </summary>
   public Boolean Extended
   {
      set
      {
         button.Extended = value;
      }

      get
      {
         return button.Extended;
      }
   }
 
   /// <summary>
   /// color change event handler
   /// </summary>
   public event ColorChangedHandler ColorChanged;
 
   public ColorComboBox()
   {
      InitializeComponent();
      //setup event handler to catch the ColorChanged message from the 
      //color popup 
      button.ColorChanged += new ColorChangedHandler(button_ColorChanged);
   }
   
   public void button_ColorChanged(object sender, ColorChangeArgs e)
   {
      if (ColorChanged != null)
      {
         ColorChanged(this, e);
      }
   }
   
   private void ColorComboBox_SizeChanged(object sender, EventArgs e)
   {
      button.Location = new Point(0, 0);
      button.Size = this.Size;
   }

}

The next control in the chain is the ColorComboButton. This is the first visible thing in this control. This is the button that shows the selected color and a drop down arrow to its right. The significant items in this class are the ColorChanged event, the ColorCombo_Click event handler, and the OnCheckStatus timer event handler.

C#
private class ColorComboButton : CheckBox

{
   private void ColorCombo_Click(object sender, EventArgs e)
   {
      //if it is already down, don't do anything.
      //this shouldn't happen anymore since we 
      //started to disable the button when the 
      //drop down is being displayed
      if (!this.Checked)
      {
             return;
      }

      //create a popup window
      popupWnd = new PopupWindow(colors);
   
      //calculate its position in screen coordinates
      Rectangle rect = Bounds;
      rect = this.Parent.RectangleToScreen(rect);
      Point pt = new System.Drawing.Point(rect.Left, rect.Bottom);
   
      //tell it that we want the ColorChanged event
      popupWnd.ColorChanged += new ColorChangedHandler(OnColorChanged);

      //show the popup
      popupWnd.Show(pt);

      //disable the button so that the user can't click it
      //while the popup is being displayed
      this.Enabled = false;
   }


   //event handler for the color change event from the popup window
   //simply relay the event to the parent control
   protected void OnColorChanged(object sender, ColorChangeArgs e)
   {
      //if a someone wants the event, and the color has actually changed
      //call the event handler
      if (ColorChanged != null && e.color != this.selectedColor)
      {
         this.selectedColor = e.color;
         ColorChanged(this, e);
      }
      else //otherwise simply make note of the new color
      {
         this.selectedColor = e.color;
      }
   }

   //This is the timer call back function. It checks to see 
   //if the popup went from a visible state to an close state
   //if so then it will uncheck and enable the button
   private void OnCheckStatus(Object myObject, EventArgs myEventArgs)
   {
      if (popupWnd != null && !popupWnd.Visible)
      {
         this.Checked = false;
         this.Enabled = true;
      }
   }
}

Next, we have the ColorPopup control, which is a User Control, and the ColorRadioButton. ColorPopup is simply a container that holds a number of flat radio buttons which have colors on them. The ColorRadioButton inherits from a RadioButton and does some custom drawing in order to show the colors in the ColorPopup. I'll let you discover those on your own, since they are extremely straightforward.

Next is the PopupWindow which inherits from ToolStripDropDown. This class has two methods, a constructor and a Close event handler. The constructor creates a ToolStripControlHost which will host the PopupColor User Control, and adds it as an item to the ToolStripDropDown's list. The Close event handler simply fires the ColorChanged event.

C#
private class PopupWindow : ToolStripDropDown
{
   public PopupWindow(ColorPopup content)
   {
       if (content == null)
      {
         throw new ArgumentNullException("content");
      }
      this.content = content;
      this.AutoSize = false;
      this.DoubleBuffered = true;
      this.ResizeRedraw = true;
      //create a host that will host the content
      host = new ToolStripControlHost(content);

      this.Padding = Margin = host.Padding = host.Margin = Padding.Empty;
      this.MinimumSize = content.MinimumSize;
      content.MinimumSize = content.Size;
      MaximumSize = new Size(content.Size.Width + 1, 
                             content.Size.Height + 1);
      content.MaximumSize = new Size(content.Size.Width + 1,
           content.Size.Height + 1);
      Size = new Size(content.Size.Width + 1, content.Size.Height + 1);

      content.Location = Point.Empty;

      //add the host to the list
      Items.Add(host);
   }

   protected override void OnClosed(ToolStripDropDownClosedEventArgs e)
   {
      //when the window close tell the parent that the color changed
      if (ColorChanged != null)
      {
         ColorChanged(this, new ColorChangeArgs(this.SelectedColor));
      }
   }
}

Using the code

The use of the control is pretty straightforward. I didn't create a Class Library because it would be overkill for one control. So, simply copy and paste the three files in ColorComboBox.zip into your projects directory and add them to your project. You might have to do a build before the control will be displayed in the control toolbox. Once it is there, you can simply drag and drop it into a WinForm.

The control has two extra properties, SelectedColor and Extended. The SelectedColor property is used for getting and setting the selected color in the ColorComboBox. The Extended property changes the contents of the drop down box form a basic color set to an extended color set.

The control also exposes an event, ColorChanged, to notify that the user has changed the color selection.

C#
//setup the event handler

private void InitializeComponent()
{
   ...
   this.colorComboBox1.ColorChanged += 
        new ColorComboTestApp.ColorChangedHandler(this.OnColorChanged);
   ...
}

//the event handler method
protected void OnColorChanged(object sender, ColorChangeArgs e)
{
   MessageBox.Show(this,e.color.ToString(),"Selected color", 
                   MessageBoxButtons.OK, MessageBoxIcon.Information);
}

Have fun!

License

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