ColorComboBox

The Extended Color Set

The 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, because any rich text editor application would need one of these in their toolbar.

Background

Because 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 have to be detected to close the popup. I soon learned that the only way to pick up the mouse click outside of the popup window is to use a Windows Hook (you 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; this 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 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 then 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) that contains a ColorComboButton (derived from CheckBox) that contains a PopupWindow (derived from ToolStripDropDown) that contains a ColorPopup (derived from UserControl) that contains a ColorRadioButton (derived from RadioButton).

Let me get into some detail.

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

// 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.

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();
      // set up 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;
   }

}

ColorComboBox

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.

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 because 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 a closed state.
   // If so, 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, you 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 thatich have colors on them. The ColorRadioButton inherits from a RadioButton and does some custom drawing to show the colors in the ColorPopup. I'll let you discover those on your own; 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 that 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.

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 closes, 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.

// Set up 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!



About the Author

Ali Rafiee

Ali Rafiee has been developing windows applications for the past 14 years using Visual C++, and he hasn't looked back since. Ali has been a software development consultant for must of his career, but he has finally settled down and has been working for an educational software company for the past 7 years. While he is not working, he is either learning C#, flying airplanes, playing with his daughter, or answering peoples question on newsgroups, he finds that to be a great learning tool for him (He is always trying to learn something new).

Downloads

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Managing your company's financials is the backbone of your business and is vital to the long-term health and viability of your company. To continue applying the necessary financial rigor to support rapid growth, the accounting department needs the right tools to most efficiently do their job. Read this white paper to understand the 10 essentials of a complete financial management system and how the right solution can help you keep up with the rapidly changing business world.

  • If you need new tools and tricks to make your meetings profitable and productive, then 5 Tips in 5 Minutes: A Quick Guide for More Profitable Sales Meetings is for you. Timely, practical tips that you can incorporate in just seconds will save you literally hours in travel and meeting time, not to mention help you to focus on what your sales prospects really want to know and how you can meet their needs. Get 5in5: A Quick Guide for More Profitable Sales Meetings and start building your sales the smarter, faster …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds