пара идей для вас
Идея 1. Выполните выборку шрифта целиком в фоновом потоке.
Шрифты фактически загружаются в системный шрифт (межпроцессный), а затем часть информации о шрифте копируется в поток-кеш-шрифт. Вполне возможно, что заполнение кэша системных шрифтов приведет к достаточно хорошему увеличению скорости. Это может быть сделано фоновым потоком с низким приоритетом, который запускается сразу после запуска вашего приложения. Таким образом, к тому времени, когда пользователь опустит список шрифтов, кэш системного шрифта должен быть полностью заполнен.
Идея 2: Кэшировать геометрию визуализированного шрифта самостоятельно
Вместо использования TextBlocks, используйте объекты ContentPresenter в DataTemplate вашего ComboBox с содержимым, привязанным к PriorityBinding. При более низком приоритете будет создан TextBlock с использованием шрифта по умолчанию, а более высоким приоритетом будет привязка IsAsync, которая создаст GlyphRun с соответствующими параметрами, вызовет для него BuildGeometry () и вернет Geometry внутри объекта Path. Созданные объекты Geometry можно кэшировать и снова возвращать для последующего доступа к тому же шрифту.
В результате этого элементы будут первоначально отображаться шрифтом по умолчанию и визуализироваться в стилизованный шрифт, как только шрифты будут загружены и их геометрия будет создана. Обратите внимание, что это можно комбинировать с кодом, который предварительно заполняет ваш кэш в отдельном потоке.
Код для Idea 2 будет выглядеть примерно так:
<ComboBox ItemsSource="{Binding MyFontObjects}">
<ComboBox.ItemTemplate>
<ContentPresenter>
<ContentPresenter.Content>
<PriorityBinding>
<Binding IsAsync="True" Path="BuildStyledFontName" />
<Binding Path="BuildTextBlock" />
</PriorityBinding>
... close all tags ...
Где MyFontObjets будет IEnumerable объектов примерно так:
public class MyFontObject
{
public FontFamily Font { get; set; }
public object BuildTextBlock
{
get { return new TextBlock { Text = GetFamilyName(Font) } }
}
public object BuildStyledFontName
{
get
{
return new Path { Data = GetStyledFontGeometryUsingCache() };
}
}
private Geometry GetStyledFontGeometryUsingCache()
{
Geometry geo;
lock(_fontGeometryCache)
if(_fontGeometryCache.TryGetValue(Font, out geo) return geo;
lock(_fontGeometryBuildLock)
{
lock(_fontGeometryCache)
if(_fontGeometryCache.TryGetValue(Font, out geo) return geo;
geo = BuildStyledFontGeometry();
lock(_fontGeometryCache)
_fontGeometryCache[Font] = geo;
}
}
static object _fontGeometryCache = new Dictionary<FontFamily, Geometry>();
static object _fontGeometryBuildLock = new object();
private Geometry BuildStyledFontGeometry()
{
var run = new GlyphRun
{
Characters = GetFamilyName(Font),
GlyphTypeface = GetGlyphTypeface(Font),
}
return run.BuildGeometry();
}
... GetFamilyName ...
... GetGlyphTypeface ...
// Call from low priority background thread spawned at app startup
publc static void PrefillCache()
{
foreach(FontFamily font in Fonts.SystemFontFamilies)
new MyFontObject { Font = font }.GetStyledFontGeometryUsingCache();
}
}
Обратите внимание, что объекты Geometry в кэше можно сохранить на диск, преобразовав их в PathGeometry, а затем в строки на мини-языке PathGeometry. Это позволило бы заполнить кэш геометрии шрифта, используя один файл read & parse, поэтому вы могли увидеть только одну задержку, когда вы впервые запустили приложение или запустили его с большим количеством новых шрифтов.