Home > Mobile >  How can I display a friendly name for a Google Font in a WPF application?
How can I display a friendly name for a Google Font in a WPF application?

Time:01-14

I have added a Google font to my application using the method ComboBox dropdown showing system fonts and URI to Google font

I have tried something similar to the below where you list the FamilyNames in the XAML, but you're unable to add the URI as the XAML value in this case without a syntax editor.

<FontFamily x:Key="Montserrat">
    <FontFamily.FamilyNames>
            <System:String x:Key="en-US">Montserrat</System:String>
    </FontFamily.FamilyNames> 
            !!! syntax error
            pack://application:,,,/Themes/General/Fonts/#Montserrat
</FontFamily>

So, what's the best way to get this font's friendly name to show in my combobox?

CodePudding user response:

You need to Iterate over the embedded fonts, then extract the name from the Typeface object.

Here is a working demo project where I added all of the Montserrat font variations (.tff files) top the projects' .\Resources folder as Content and copy if newer. My .csproj file looks like:

  <ItemGroup>
    <Content Include="Resources\Montserrat-Black.ttf">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
    <Content Include="Resources\Montserrat-BlackItalic.ttf">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
    <Content Include="Resources\Montserrat-Bold.ttf">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
    <Content Include="Resources\Montserrat-BoldItalic.ttf">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
    <Content Include="Resources\Montserrat-ExtraBold.ttf">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
    <Content Include="Resources\Montserrat-ExtraBoldItalic.ttf">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
    <Content Include="Resources\Montserrat-ExtraLight.ttf">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
    <Content Include="Resources\Montserrat-ExtraLightItalic.ttf">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
    <Content Include="Resources\Montserrat-Italic.ttf">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
    <Content Include="Resources\Montserrat-Light.ttf">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
    <Content Include="Resources\Montserrat-LightItalic.ttf">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
    <Content Include="Resources\Montserrat-Medium.ttf">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
    <Content Include="Resources\Montserrat-MediumItalic.ttf">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
    <Content Include="Resources\Montserrat-Regular.ttf">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
    <Content Include="Resources\Montserrat-SemiBold.ttf">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
    <Content Include="Resources\Montserrat-SemiBoldItalic.ttf">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
    <Content Include="Resources\Montserrat-Thin.ttf">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
    <Content Include="Resources\Montserrat-ThinItalic.ttf">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
  </ItemGroup>

Here is the code-behind:

public partial class MainWindow : Window, INotifyPropertyChanged
{
    private string selectedFontName;
    private string fontFamilyPath;

    private static string uriPath= @"pack://application:,,,/";
    private static string resPath = "./resources/";

    public MainWindow()
    {
        InitializeComponent();
        GetFontNames();
        SetDefontFont();
    }

    public ObservableCollection<string> FontNames { get; } = new();

    public string SelectedFontName
    {
        get => selectedFontName;
        set
        {
            SetFontFamilyPath(value);
            Set(ref selectedFontName, value);
        }
    }

    public string FontFamilyPath
    {
        get => fontFamilyPath;
        set => Set(ref fontFamilyPath, value);
    }

    private void GetFontNames()
    {
        foreach (Typeface typeface in Fonts.GetTypefaces(new Uri(uriPath), resPath))
        {
            string typefaceName = typeface.FontFamily.FamilyNames.First().Value;

            foreach (KeyValuePair<XmlLanguage, string> weight in typeface.FaceNames)
            {
                // get type weight name
                string typeWeightName = weight.Value;

                // get type weight value
                int? typeWeightValue = typeface
                    .FontFamily
                    .FamilyTypefaces
                    .ToList() // convert collection to List for working with Linq
                    .FirstOrDefault(x => x.Weight.ToString().Equals(weight.Value) &&
                                         x.Weight.ToOpenTypeWeight() > 0)?
                    .Weight
                    .ToOpenTypeWeight();

                FontNames.Add($"{typefaceName} {typeWeightName}{(typeWeightValue is null ? "" : $" ({typeWeightValue})")}");
            }
        }
    }

    private void SetDefontFont()
        => SetFontFamilyPath(FontNames.First());

    private void SetFontFamilyPath(string name)
        => FontFamilyPath = $"./Resources/#{name}";

    public event PropertyChangedEventHandler? PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
        => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

    protected bool Set<T>(ref T field, T value, [CallerMemberName] string? propertyName = null)
    {
        if (EqualityComparer<T>.Default.Equals(field, value)) return false;
        field = value;
        OnPropertyChanged(propertyName);
        return true;
    }
}

and here is the Window:

<Window x:Class="WpfEmbeddedGoogleTtfFont.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfEmbeddedGoogleTtfFont"
        mc:Ignorable="d" x:Name="Window"
        Title="MainWindow" Height="450" Width="800">
    <Grid DataContext="{Binding ElementName=Window}">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition />
        </Grid.RowDefinitions>
        <TextBlock Text="The quick brown fox..."
                   FontFamily="{Binding FontFamilyPath}" FontSize="32" />
        <ListBox Grid.Row="1"
                 ItemsSource="{Binding FontNames}"
                 SelectedItem="{Binding SelectedFontName}"/>
    </Grid>
</Window>

The sample project will extract all of the embedded fonts with their weight names values and display in a list. You can then select the font and the sample text will use it.

enter image description here

enter image description here

  • Related