This article shows how to use the built in ownerdraw
functionality of a standard Windows Forms ComboBox control to
display a WYSIWYG font list.
Setting up the control
To start, we'll create a new class, and inherit this from the
ComboBox control.
We are going to use variable ownerdraw for this sample, as it
gives us a little more flexibility without having to mess around
with the ItemHeight property. We'll add a constructor, and set
the ownerdraw mode here. Also, we'll add a new version of the
DrawMode property, which we'll both hide and disable the value
persistence. We always want the font list to be sorted, so for
now we'll do the same with the Sorted property.
Caching Font objects
In order to avoid continuously creating and destroying font
objects, we'll create a internal cache of fonts. When it's time
to draw the control, the cache will be queried - if the
requested font exists, it will be returned, otherwise the font
will be created and added to the cache. This will be done via
the GetFont method below.
Note: Whilst testing the control, I discovered that some of
the fonts installed on the development system only had bold or
italic styles. The original version of this method, which
always attempts to get the normal style would cause a crash.
Due to this, I changed the method to try and access the normal
style, and if that failed, to try the other styles. Perhaps
there is a better way of doing this, but I leave that as an
exercise for the future.
As we don't want the font size of the dropdown list to
necessarily match that of the display/edit portion, we'll add a
new property named `PreviewFontSize*.
When certain actions occur, such as this property changing, we
want to calculate the height of items in the dropdown list.
Loading the list of font families
In order to avoid slowing the control down without reason, we'll
delay loading the list of font families until there is a reason,
either when the control's text has changed, or when the control
gets focus.
This will be done by creating a LoadFontFamilies method which
will be called by overriding OnGotFocus and OnTextChanged.
Drawing the items
Drawing an overdraw ComboBox is done by overriding the
OnDrawItem method. However, as we have told the control we are
doing variable sized ownerdraw, we also need to override
OnMeasureItem. This method allows us to define the size for
each item, or in the case of this control to set the height of
each item to match the pixel height calculated for the value of
the PreviewFontSize property.
The actual drawing is very simple - we use the built in drawing
for the background and focus rectangle, and then use the
Graphics object to draw the text using the GetFont method
explained above.
You might notice that the above code is referencing a previously
defined StringFormat object. This is created using the below
method.
Cleaning up
As we are creating a large number of objects, we need to clean
these up in the controls Dispose method.
Suggestions for improvement
The control as it stands is a basic example, and depending on
your application's needs, it could be further expanded. For
example:
Currently each instance of the control will use its own font
cache. By making the cache and access methods static, a single
cache could be used by all instances
When you select a font in Word, this is added to a kind of
"recently used" list at the top of Word's own font picker. The
same sort of functionality could be quite easily added to this
control.
Currently the font text is displayed on a single line. If the
control isn't wide enough, the text is trimmed and therefore
it may not be always possible to tell the full name of a font.
Either tooltip support or drawing across multiple lines could
help with this, or by resizing the dropdown component to be
the minimum width required to display all font names without
trimming.
Full source
The full source of the class is below.
Update History
2011-02-19 - First published
2020-11-21 - Updated formatting
Like what you're reading? Perhaps you like to buy us a coffee?
[b]Creating a WYSIWYG font ComboBox using C#[/b]
Creating a WYSIWYG font ComboBox using C# excerpt=You've been kicked (a good thing) - Trackback from DotNetKicks.com
I noticed that you've used GDI++ to draw the text.
It is widely known that GDI++ does not support OpenType fonts or Rastered fonts and consequently those fonts would not show up in the box.
Previously I wrote an article about P/Invoking Windows GDI to render those 'unsupported' fonts, in which you may also feel interested. http://www.codeproject.com/Tips/557423/Rendering-Text-with-OpenType-Fonts-Using-GDI
Many thanks for the link. I stopped using Graphics.DrawString myself some time ago (either using TextRenderer or using DrawText, DrawTextEx and TextOut directly). I wasn't aware that GDI+ didn't support some fonts properly, I stopped using it because it looks bloody awful and has no consistency with the rest of the OS :)
No, I didn't do a sample for this project. Think of it as a list of font names, just drawn prettier. It doesn't handle creation of fonts for you, it's purpose was to allow the selection of a font name in conjunction with other controls for selecting styles, size etc. The Items collection holds all those names, so you can use SelectedItem to return the selected name and so on.
The founder of Cyotek, Richard enjoys creating new blog content for the site. Much more though, he likes to develop programs, and can often found writing reams of code. A long term gamer, he has aspirations in one day creating an epic video game - but until that time comes, he is mostly content with adding new bugs to WebCopy and the other Cyotek products.
# DotNetKicks.com
# DotNetShoutout
# wmjordan
# Richard Moss
# Roy
# Richard Moss