Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Using Font Icons

0.00/5 (No votes)
12 Aug 2013 1  
This tip helps in using font icons as ImageSource.

Introduction

This tip gives a solution to use font icons in most of WPF controls (like Ribbon).

Background

I recently worked on using a ribbon in a WPF application. The problem is that the ribbon only permits to use ImageSource to display icons. My aim is to use a font icon library (like in HTML) because it contains vector icons and the final application is homogeneous.

In the sample, you will find the Font:

Using the Code

  1. Create a new WPF Project (can be MVVM).
  2. Create a ribbon (Add reference to System.Windows.Controls.Ribbon).
  3. Embed a font that will contain scalable icons:
    1. From your Resource.resx, add the ttf file
    2. In solution explorer, find the TTF file and change the "Build action" to "Resource"
  4. Add reference to WpfTools (in download package)
  5. Use font icons as ImageSource

To display an icon from a font:

<RibbonButton Label="Import data" 
  LargeImageSource="{WpfTools:ImageFromFont Text=&#xf01a;, 
  FontFamily=/RibbonFontIconSample;component/Resources/#FontAwesome, Brush=Brown}" /> 

Use the following parameters:

  • Text: The character representing the icon (depending on the font. For FontAwesome, I used the CheatSheet http://fortawesome.github.io/Font-Awesome/cheatsheet/ to get code.
  • FontFamily to choose the embedded font (use the syntax below)
  • Brush used to colorize icon (can be a Color or a static resource)
  • Style for italic
  • Weight for bold

Points of Interest

This class can be used with any controls which have an ImageSource property (Ribbon, Image, ...).

It is a way to have high definition icons in application because they are scalable vector icons.

How It Works

As you cannot override ImageSource one of the solutions is to create a MarkupExtension.

A markup extension is a class that can be used in XAML code inside { } and as only one pure abstract method ProvideValue which is called to get the resulting object.

public override object ProvideValue(IServiceProvider serviceProvider)
{
    return CreateGlyph(Text, FontFamily, Style, Weight, Stretch, Brush);
}   

In WPF, one way to render a string as a drawable object is to use Glyph (and GlyphRun).

A glyph is a way to render one or more characters in a scalar way. It uses a Font and character index to draw one letter or icon.

Here is the code that draws a text into ImageSource:

private static ImageSource CreateGlyph(string text, 
        FontFamily fontFamily, FontStyle fontStyle, FontWeight fontWeight, 
        FontStretch fontStretch, Brush foreBrush)
{
    if (fontFamily != null && !String.IsNullOrEmpty(text))
    {
        Typeface typeface = new Typeface(fontFamily, fontStyle, fontWeight, fontStretch);
        GlyphTypeface glyphTypeface;
        if (!typeface.TryGetGlyphTypeface(out glyphTypeface))
                throw new InvalidOperationException("No glyphtypeface found");

        ushort[] glyphIndexes = new ushort[text.Length];
        double[] advanceWidths = new double[text.Length];
        for (int n = 0; n < text.Length; n++)
        {
            ushort glyphIndex = glyphTypeface.CharacterToGlyphMap[text[n]];
            glyphIndexes[n] = glyphIndex;
            double width = glyphTypeface.AdvanceWidths[glyphIndex] * 1.0;
            advanceWidths[n] = width;
        }

        GlyphRun gr = new GlyphRun(glyphTypeface, 0, false, 1.0, glyphIndexes,
                                    new Point(0, 0), advanceWidths, 
                                    null, null, null, null, null, null);
        GlyphRunDrawing glyphRunDrawing = new GlyphRunDrawing(foreBrush, gr);
        return new DrawingImage(glyphRunDrawing);

    }
    return null;
}

Limitations

All the properties (Text, FontFamily, Brush) are not bindable (due to MarkupExtension which is not a DependencyObject).

The size is not directly managed, because the glyph is rendered to stretch in the container object.

You have to put the class in a separate assembly (like WpfTool) to make it work in design mode (it is a known bug of Visual Studio).

History

  • 08/2013: First version

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here