
Introduction
I wrote this code one afternoon when I had some free time. I wanted to see how long it would take me to figure out how to enumerate through all the fonts in the system, then use those fonts to paint the associated entries in a combobox. Having finished the code, I decided the project might make for a good CodeProject article.
Using the code
For the most part, the control should be used like any other .NET custom control. The only thing to keep in mind is that I derived it from System.Windows.Forms.Control instead of System.Windows.Forms.ComboBox, so the properties and events will not be the same as a standard combobox. I made that decision because I felt that if I exposed the collection of combobox items, it would be too hard to manage the list of associated FontFamily objects. Honestly, I had visions of someone adding a non-existent font to the collection and leaving me to deal with the consequences - yuck. :o(
The only event is the 'SelectedIndexChanged' event, which is fired whenever a font name is selected in the combobox.
The only properties of any interest are:
- The '
SelectedFontFamily' property, which is a runtime property for getting/setting the selected font in the combobox.
- The '
SelectedIndex' property, which is a runtime property for getting/setting the selected index in the combobox.
To use the control in your code, just drop it on a form, wire up the SelectedIndexChanged event in the Visual Studio event designer, and add some code to respond to changes in the state of the control. Here is a demonstration of the SelectedIndexChanged handler from the sample application:
private void m_fontCombo_SelectedIndexChanged(object sender, System.EventArgs e)
{
MessageBox.Show(
this,
"You selected: " + m_fontCombo.SelectedFontFamily.Name
);
}
Points of Interest
There are two interesting internal parts to the control. The first is the code used to enumerate through the list of installed fonts:
private void CreateSampleFonts()
{
if (!IsHandleCreated || DesignMode)
return;
if (m_comboBox.Items.Count > 0)
{
for (int x = 0; x < m_comboBox.Items.Count; x++)
((Font)m_comboBox.Items[x]).Dispose();
m_comboBox.Items.Clear();
}
FontFamily[] ff = FontFamily.Families;
for (int x = 0; x < ff.Length; x++)
{
System.Drawing.Font font = null;
if (ff[x].IsStyleAvailable(FontStyle.Regular))
font = new System.Drawing.Font(
ff[x].Name,
m_comboBox.Font.Size
);
else if (ff[x].IsStyleAvailable(FontStyle.Bold))
font = new System.Drawing.Font(
ff[x].Name,
m_comboBox.Font.Size,
FontStyle.Bold
);
else if (ff[x].IsStyleAvailable(FontStyle.Italic))
font = new System.Drawing.Font(
ff[x].Name,
m_comboBox.Font.Size,
FontStyle.Italic
);
else if (ff[x].IsStyleAvailable(FontStyle.Strikeout))
font = new System.Drawing.Font(
ff[x].Name,
m_comboBox.Font.Size,
FontStyle.Strikeout
);
else if (ff[x].IsStyleAvailable(FontStyle.Underline))
font = new System.Drawing.Font(
ff[x].Name,
m_comboBox.Font.Size,
FontStyle.Underline
);
if (font != null)
m_comboBox.Items.Add(font);
}
}
The FontFamily class makes the enumeration process trivial. Man I love C#! :o)
The second interesting part of the control is the code for actually painting the font entries:
private void m_comboBox_DrawItem(object sender, DrawItemEventArgs e)
{
if (e.Index == -1 || e.Index >= m_comboBox.Items.Count)
return;
e.DrawBackground();
if ((e.State & DrawItemState.Focus) != 0)
e.DrawFocusRectangle();
Brush b = null;
try
{
b = new SolidBrush(e.ForeColor);
e.Graphics.DrawString(
((Font)m_comboBox.Items[e.Index]).Name,
((Font)m_comboBox.Items[e.Index]),
b,
e.Bounds
);
}
finally
{
if (b != null)
b.Dispose();
b = null;
}
}
All I really have to do is keep track of the item index and use that value to locate the proper FontFamily object. From there, it is simply a matter to draw the name of the font to the screen.
Conclusion
To be sure, there is a little more going on inside the control. However, most of it relates to forwarding events and properties to the embedded combobox control. Pretty boring stuff.
This code is new, and relatively untested. If you find bugs, just let me know and I'll do my best to squash them.
Have fun! :o)