In WPF we would like to use ttf fonts as embedded resources without copying or installing these to the system and without actually writing these to disk. Withou
I don't know if this is exactly what you want, but I got a solution where you can use your fonts as a Resource in your solution.
fonts you want as Resource.MarkupExtension called FontExplorerXAML ExampleWhen the application starts and the FontExplorer is used for the first time, it caches all fonts which you have as resource. After that, everytime you need one of it, the cache is used to give it back.
public class FontExplorer : MarkupExtension
{
// ##############################################################################################################################
// Properties
// ##############################################################################################################################
#region Properties
// ##########################################################################################
// Public Properties
// ##########################################################################################
public string Key { get; set; }
// ##########################################################################################
// Private Properties
// ##########################################################################################
private static readonly Dictionary<string, FontFamily> _CachedFonts = new Dictionary<string, FontFamily>();
#endregion
// ##############################################################################################################################
// Constructor
// ##############################################################################################################################
#region Constructor
static FontExplorer()
{
foreach (FontFamily fontFamily in Fonts.GetFontFamilies(new Uri("pack://application:,,,/"), "./Fonts/"))
{
_CachedFonts.Add(fontFamily.FamilyNames.First().Value, fontFamily);
}
}
#endregion
// ##############################################################################################################################
// methods
// ##############################################################################################################################
#region methods
public override object ProvideValue(IServiceProvider serviceProvider)
{
return ReadFont();
}
private object ReadFont()
{
if (!string.IsNullOrEmpty(Key))
{
if (_CachedFonts.ContainsKey(Key))
return _CachedFonts[Key];
}
return new FontFamily("Comic Sans MS");
}
#endregion
}
<Window x:Class="WpfApp1.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:WpfApp1"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance local:MainWindow}"
Title="MainWindow" Height="450" Width="800">
<Window.Style>
<Style TargetType="local:MainWindow">
<Setter Property="FontFamily" Value="{local:FontExplorer Key='Candle Mustard'}"/>
<Style.Triggers>
<Trigger Property="Switch" Value="True">
<Setter Property="FontFamily" Value="{local:FontExplorer Key=Roboto}"/>
</Trigger>
</Style.Triggers>
</Style>
</Window.Style>
<Grid x:Name="grid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackPanel Orientation="Vertical" VerticalAlignment="Center" HorizontalAlignment="Center" Grid.Column="0">
<TextBlock Text="Hello World" FontFamily="{local:FontExplorer Key='Candle Mustard'}"/>
<TextBlock Text="Hello World" FontFamily="{local:FontExplorer Key=Roboto}"/>
<TextBlock Text="Hello World"/>
<TextBlock Text="Hello World"/>
<TextBlock Text="Hello World"/>
<TextBlock Text="Hello World"/>
<TextBlock Text="Hello World"/>
<TextBlock Text="Hello World"/>
<TextBlock Text="Hello World"/>
<TextBlock Text="Hello World"/>
<TextBlock Text="Hello World"/>
<TextBlock Text="Hello World"/>
</StackPanel>
<StackPanel Orientation="Vertical" VerticalAlignment="Center" HorizontalAlignment="Center" Grid.Column="1" x:Name="Panel"/>
</Grid>
</Window>
public partial class MainWindow : Window
{
public bool Switch
{
get => (bool)GetValue(SwitchProperty);
set => SetValue(SwitchProperty, value);
}
/// <summary>
/// The <see cref="Switch"/> DependencyProperty.
/// </summary>
public static readonly DependencyProperty SwitchProperty = DependencyProperty.Register("Switch", typeof(bool), typeof(MainWindow), new PropertyMetadata(false));
private readonly DispatcherTimer _Timer;
public MainWindow()
{
InitializeComponent();
_Timer = new DispatcherTimer();
_Timer.Interval = TimeSpan.FromMilliseconds(50);
_Timer.Tick += (sender, args) =>
{
Switch = !Switch;
Panel.Children.Add(new TextBlock {Text = "I'm frome code behind"});
if(Panel.Children.Count > 15)
Panel.Children.Clear();
};
_Timer.Start();
}
// ##############################################################################################################################
// PropertyChanged
// ##############################################################################################################################
#region PropertyChanged
/// <summary>
/// The PropertyChanged Eventhandler
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Raise/invoke the propertyChanged event!
/// </summary>
/// <param name="propertyName"></param>
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
As you can see in the preview, the memory usage reduces from 83,2MB to 82,9 MB after the GC does it's job.