Extending the ComboBox with C#

Ever needed to do something with the ComboBox, but found that the normal ComboBox is quite limited? The ComboBox, as we know it, shows a list of items. What if you wanted to show colours, fonts, drawn lines, or images with the ComboBox? Wouldn’t that be nice? Yes, it would. Not only that, but why not change the appearance and normal behaviour of the normal ComboBox? In this article, I will demonstrate how to do all these and more with the ComboBox.

Your Project: CrazyCombos

As the name implies, you are really going to go a bit crazy with extending the ComboBox’s uses.

Create a new Windows Forms project, named CazyCombos.

Fonts Combo

The first thing that I will cover is creating a Font ComboBox. A Font ComboBox displays a list of all the available fonts on the user’s PC, similar to what you use to change the Font in MS Word or MS Excel, for example. Apart from listing the available fonts, you also can display a small sample of each particular font by writing the current font name with the current font. For example, if you want to display Comic Sans MS, you must use the Comic Sans MS font to write Comic sans MS; in other words, the name of the font.

To create a Font ComboBox, follow these steps:

  1. Click Project.
  2. Click Add Class…
  3. Name the class FontCbo.cs.

This class will create a new font.

Import the Drawing Namespace at the top of FontCbo.cs.

using System.Drawing;    //Import Drawing NameSpace

Create a Font object:

public Font FCFont;      //Font Used

Edit the Class constructor as follows:

public FontCbo(Font FCCurrFont)
{
   //Set This Font Equal To Font Supplied
   FCFont = FCCurrFont;
}

Override the built-in ToString method to display the current font’s name:

   /// <summary>
   /// Override ToString Method To Display Current Font's Name
   /// </summary>
   /// <returns></returns>
public override string ToString()
{
    return FCFont.Name;    //Display Font Name
}

Build your project.

Go to frmCrazy’s Design view and add a ComboBox named cboFontsCrazy to it. Set cboFontsCrazy’s DrawMode property to OwnerDrawVariable. This enables you to display custom items in the list. Add the following variable to frmCrazy:

   private SolidBrush FontForeColour;    //Font's Colour

Load All the Fonts

In frmCrazy_Load add the following:

//FontCombo
//Obtain & Store System fonts Into Array
FontFamily[] families = FontFamily.Families;

//Loop Through System Fonts
foreach (FontFamily family in families)
{
//Set Current Font's Style To bold
   FontStyle style = FontStyle.Bold;

   //These Are Only Available In Italic, Not In "Regular",
   //So Test For Them, Else, Exception!!
   if (family.Name   == "Monotype Corsiva"
      || family.Name == "Brush Script MT"
      || family.Name == "Harlow Solid Italic"
      || family.Name == "Palace Script MT" ||
      family.Name    == "Vivaldi")
   {
      //Set Style To Italic, To Overt "Regular" & Exception
      style = style | FontStyle.Italic;
   }
   //Display The Font Combo Items
   cboFontsCrazy.Items.Add(new FontCbo(new Font(family.Name, 12,
                           style, GraphicsUnit.Point)));
}

Here, you created an array to store all the system’s fonts, and then you looped through all of them. As you loop, you set each font’s style to Bold, so that it appears Bold in FontCbo. The interesting thing here to note is that not all of the fonts support the Bold style, not even the Regular font style. What I had to do was to wait for the program to give me errors on the particular font(s) name(s). On each of the fonts in the if block, I received an error that they don’t support the regular or Bold styles. This meant that each of those fonts only support italic; that is why I had to identify them, tand hen change their styles to italic. You could have set the style just to italic in the first place, but still you may have received errors on fonts not supporting Bold. So, it is basically trial and error.

The physical drawing of each font happens in the cboFontsCrazy_DrawItem event:

/// <summary>
/// Drawing Of Fonts
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void cboFontsCrazy_DrawItem(object sender,
                                    DrawItemEventArgs e)
{
   Brush FontBrush;    //Brush To Be used

   //If No Current Colour
   if (FontForeColour == null)
   {
      //Set ForeColour
      FontForeColour = new SolidBrush(e.ForeColor);
   }
   else
   {
      //Fore Colour Changed, Create New Brush
      if (!FontForeColour.Color.Equals(e.ForeColor))
      {
         FontForeColour.Dispose();   //Dispose Old Brush
         //Create New Brush
         FontForeColour = new SolidBrush(e.ForeColor);
     }
   }

   //Set Appropriate Brush
   if ((e.State & DrawItemState.Selected) ==
        DrawItemState.Selected)
   {
      FontBrush = SystemBrushes.HighlightText;
   }
   else
   {
      FontBrush = FontForeColour;
   }

   //Current item's Font
   Font font = ((FontCbo)cboFontsCrazy.Items[e.Index]).FCFont;

   e.DrawBackground();    //Redraw Item Background

   //Draw Current Font
   e.Graphics.DrawString(font.Name, font, FontBrush, e.Bounds.X,
                         e.Bounds.Y);

   e.DrawFocusRectangle();    //Draw Focus Rectangle Around It

}

Edit the cboFontsCrazy_MeasureItem event to look like:

/// <summary>
/// Item Height Measurements
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void cboFontsCrazy_MeasureItem(object sender,
                                       MeasureItemEventArgs e)
{
   //Get Current Font In ComboBox
    Font font = ((FontCbo)cboFontsCrazy.Items[e.Index]).FCFont;

   //determine Its Size
   SizeF stringSize = e.Graphics.MeasureString(font.Name, font);

   //Set Appropriate Height
   e.ItemHeight = (int)stringSize.Height;
   //Set Appropriate Width
   e.ItemWidth  = (int)stringSize.Width;

}

You can build and run your program now, and test your Fonts ComboBox. If everything went well, you should be able to display and select Fonts, as displayed in Figure 1.

Figure 1: The Working Fonts ComboBox

More by Author

Must Read