FontAwesome est une font comprenant un peu plus de 500 icônes. Cette font est très utilisée pour le web.

Mais elle peut également être utilisée pour des applications WPF. C’est ce que nous allons voir dans cet article.

Etape 1 : inclure la font

La première étape est bien évidemment de télécharger la font et d’inclure le fichier TTF en tant que resource du projet (lien direct) :

solution explorer

Nous pouvons maintenant déclarer la Font dans les resources WPF :

<Window …>     
   <Window.Resources>     
   <FontFamily x:Key="FontAwesome">pack://application:,,,/Resources/#fontawesome</FontFamily>     
   </Window.Resources>     
   
   <Grid>     
   <TextBlock Text="&#xf0fc;" FontFamily="{StaticResource FontAwesome}" FontSize="60" />     
   </Grid>     
</Window>

Voilà ce que ce bout de XAML affiche :

demo

Ok, le résultat est là mais ce n’est absolument pas pratique à utiliser car la valeur unicode n’est pas très explicite. La liste des associations nom-valeur est disponible dans le fichier less “variables. less” ou le fichier sass “_variables. scss” (disponible dans l’archive zip téléchargée au début). Ces variables se présentent sous la forme suivante :

@fa-var-adjust: "\f042";     
@fa-var-adn: "\f170";     
@fa-var-align-center: "\f037";     
@fa-var-align-justify: "\f039";     
@fa-var-align-left: "\f036";

Nous allons donc exploiter ce fichier pour simplifier l’usage de FontAwesome.

Etape 2 : Simplifier l’usage avec un T4

L’idée est d’utiliser un fichier T4 pour générer un fichier C# à partir du fichier less “variables. less”. Le fichier T4 est sur GitHub :

fontawesome demo

Le code généré par le T4 permet de récupérer les associations de 3 façons différentes :

  • Via une énumération
public enum FontAwesomeIconEnum     
{    
   /// <summary>     
   /// fa-adjust icon (f042)     
   /// </summary>     
   Adjust = 0xf042,    
   /// <summary>     
   /// fa-adn icon (f170)     
   /// </summary>     
   Adn = 0xf170,}
  • Via une liste de constantes
public static partial class FontAwesomeIcons     
{    
   /// <summary>     
   /// fa-adjust icon (f042)     
   /// </summary>     
   public const string Adjust = "\uf042";    
   /// <summary>     
   /// fa-adn icon (f170)     
   /// </summary>     
   public const string Adn = "\uf170";    
   /// <summary>     
   /// fa-align-center icon (f037)     
   /// </summary>     
   public const string AlignCenter = "\uf037";}
  • Via un Dictionary :
public static partial class FontAwesomeIcons     
{     
   private static IDictionary<string, string> _allIcons;    
   public static IDictionary<string, string> AllIcons     
   {     
   get { return _allIcons; }     
   }    
   static FontAwesomeIcons()     
   {     
   _allIcons = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);     
   _allIcons.Add("adjust", "\uf042");     
   _allIcons.Add("adn", "\uf170");     
   _allIcons.Add("align-center", "\uf037");     
   _allIcons.Add("AlignCenter", "\uf037");}    
}

Selon le besoin vous pouvez désactiver. Pour cela il faut modifier le fichier T4 :

const bool generateEnum = true;     
const bool generateConstants = true;     
const bool generateDictionary = true;

Cette longue liste de constante peut donc être utilisée directement en XAML :

<TextBlock Text="{x:Static local:FontAwesomeIcons.Beer}" FontFamily="{StaticResource FontAwesome}"/>

C’est donc beaucoup plus lisible et il n’y a pas de risque d’utiliser une icône qui n’existe pas.

Etape 3 : Simplifier encore plus l’usage avec une MarkupExtension

Dans un précédent article sur les énumérations avec WPF, j’avais déjà présenté les MarkupExtensions. C’est encore l’occasion de resortir cette arme magique pour simplifier le code :

[MarkupExtensionReturnType(typeof(string))]     
   public partial class IconExtension : MarkupExtension     
   {     
   public IconExtension()     
   {     
   }     
   
   public IconExtension(FontAwesomeIconEnum icon)     
   {     
   Icon = icon;     
   }     
   
   [ConstructorArgument("icon")]     
   public FontAwesomeIconEnum Icon { get; set; }    
   public override object ProvideValue(IServiceProvider serviceProvider)     
   {     
   return ((char)Icon).ToString();     
   }     
   }

Cela permet d’écrire le code XAML suivant :

<TextBlock Text="{local:Icon Beer}" FontFamily="{StaticResource FontAwesome}" />

Le gain est minime mais bon c’est toujours ça 🙂

Bonus : Animation fa-spin et fa-pulse

la classe CSS fa-spin permet de créer une animation de type rotation. WPF prend aussi en charge les animations, il est donc possible d’obtenir le même résultat qu’en CSS

démo

<TextBlock Text="{local:Icon Spinner}" FontFamily="{StaticResource FontAwesome}" VerticalAlignment="Center" HorizontalAlignment="Center">     
   <TextBlock.Style>     
   <Style TargetType="TextBlock">     
   <Setter Property="RenderTransformOrigin" Value="0.5 0.5"/>     
   <Setter Property="RenderTransform">     
   <Setter.Value>     
   <RotateTransform Angle="0"/>     
   </Setter.Value>     
   </Setter>     
   <Style.Triggers>     
   <EventTrigger RoutedEvent="Loaded">     
   <BeginStoryboard>     
   <Storyboard>     
   <DoubleAnimation Storyboard.TargetProperty="(UIElement.RenderTransform).(RotateTransform.Angle)"     
   From="0"     
   To="360"     
   Duration="0:0:2"     
   RepeatBehavior="Forever"/>     
   </Storyboard>     
   </BeginStoryboard>     
   </EventTrigger>     
   </Style.Triggers>     
   </Style>     
   </TextBlock.Style>

Pour fa-pulse il faut diviser l’animation de la rotation en 8 étapes (soit 45° à chaque étape) :

<TextBlock Text="{local:Icon Spinner}" FontFamily="{StaticResource FontAwesome}" VerticalAlignment="Center" HorizontalAlignment="Center">     
   <TextBlock.Style>     
   <Style TargetType="TextBlock">     
   <Setter Property="RenderTransformOrigin" Value="0.5 0.5"/>     
   <Setter Property="RenderTransform">     
   <Setter.Value>     
   <RotateTransform Angle="0"/>     
   </Setter.Value>     
   </Setter>     
   <Style.Triggers>     
   <EventTrigger RoutedEvent="Loaded">     
   <BeginStoryboard>     
   <Storyboard>    
   <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(RotateTransform.Angle)"     
   Duration="0:0:1"     
   RepeatBehavior="Forever">     
   <DiscreteDoubleKeyFrame Value="45" KeyTime="Uniform"/>     
   <DiscreteDoubleKeyFrame Value="90" KeyTime="Uniform"/>     
   <DiscreteDoubleKeyFrame Value="135" KeyTime="Uniform"/>     
   <DiscreteDoubleKeyFrame Value="180" KeyTime="Uniform"/>     
   <DiscreteDoubleKeyFrame Value="225" KeyTime="Uniform"/>     
   <DiscreteDoubleKeyFrame Value="270" KeyTime="Uniform"/>     
   <DiscreteDoubleKeyFrame Value="315" KeyTime="Uniform"/>     
   <DiscreteDoubleKeyFrame Value="360" KeyTime="Uniform"/>     
   </DoubleAnimationUsingKeyFrames>     
   </Storyboard>     
   </BeginStoryboard>     
   </EventTrigger>     
   </Style.Triggers>     
   </Style>     
   </TextBlock.Style>     
</TextBlock>

Le code complet est disponible sur GitHub : https://github.com/meziantou/WPFFontAwesome

Ne ratez plus aucunes actualités avec la newsletter mensuelle de SoftFluent