在后台线程上渲染字体并将其加载到 FontCache 中?
我试图显示类似于 Blend 中的字体选择器列表:
Blend Font Picker http ://img691.imageshack.us/img691/60/blendfontpicker.png
与 Blend 一样,当 FontFamilies 未加载到 FontCache 中时,我会遇到性能问题。
看来我付出的代价是实际渲染给定 FontSize 的 FontFamily 并将其保存到 FontCache 中所需的时间。一旦渲染的字体进入缓存,问题就消失了。
我尝试在后台线程上迭代 Fonts.SystemFontFamilies 集合,并分派对 UI 的调用,这会导致隐藏的 TextBlock 更新(这应该会导致字体呈现)。
当然,由于调度调用是连续发生的,它只会影响 UI,并且我会得到与阻塞 UI 相同的最终结果,直到所有字体都已渲染并加载到 FontCache 中。
有人对这个问题有好的解决办法吗?他们似乎没有在 Blend 中找到解决方案,所以我认为没有一个好的解决方案。
I am trying to show a Font picker list similar to the one in Blend:
Blend Font Picker http://img691.imageshack.us/img691/60/blendfontpicker.png
Like Blend, I am seeing performance issues when the FontFamilies are not loaded in the FontCache.
It seems that the penalty I am paying is the time it takes to actually render the FontFamily for the given FontSize and save it into the FontCache. Once the rendered font is in the cache the problem goes away.
I have tried iterating the Fonts.SystemFontFamilies collection on a background thread and dispatching a call to the UI which causes a hidden TextBlock to update (which should cause the font to render).
Of course, since the dispatch calls happen in succession it just pounds the UI and I get the same net result of a blocking UI until all the fonts have been rendered and loaded into the FontCache.
Does anybody have a good solution to this issue? They didn't seem to find a fix for it in Blend so I am thinking there isn't a good solution.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
给你一些想法
想法1:完全在后台线程上获取字体。
字体实际上被加载到系统字体缓存中(进程间),然后复制部分字体信息进入线程特定的字体缓存。填充系统字体缓存可能会带来足够好的速度提升。这可以通过低优先级后台线程来完成,该线程在应用程序启动时立即开始运行。因此,当用户下拉字体列表时,系统字体缓存应该已完全填充。
想法 2:自己缓存渲染的字体几何图形
不要使用 TextBlock,而是使用 ComboBox 的 DataTemplate 中的 ContentPresenter 对象,并将内容绑定到 PriorityBinding。较低优先级将使用默认字体生成 TextBlock,较高优先级将是 IsAsync 绑定,它将使用适当的参数创建 GlyphRun,对其调用 BuildGeometry(),并返回 Path 对象内的 Geometry。创建的 Geometry 对象可以被缓存并再次返回,以便将来访问相同的字体。
这样做的结果将是,项目最初将以默认字体显示,并在加载字体并创建其几何图形后立即渲染为样式字体。请注意,这可以与在单独线程中预填充缓存的代码结合使用。
想法 2 的代码看起来像这样:
其中 MyFontObjets 将是一个 IEnumerable 的对象,如下所示:
请注意,缓存中的 Geometry 对象可以通过将它们转换为 PathGeometry,然后转换为 PathGeometry mini 中的字符串来保存到磁盘。语言。这将允许使用单个文件读取和填充来填充字体几何缓存。解析,因此您唯一会看到任何延迟的是当您第一次运行应用程序时,或者当您使用大量新字体运行它时。
A couple of ideas for you
Idea 1: Do the font fetching entirely on the background thread.
The fonts are actually loaded into the system font cache (inter-process) and then part of the font information is copied into the thread-specific font cache. It is possible that filling the system font cache would result in a good enough increase in speed. This could be done by a low priority background thread that starts running the instant your app is started. So by the time the user drops down the font list the system font cache should be fully populated.
Idea 2: Cache the rendered font geometry yourself
Instead of using TextBlocks, use ContentPresenter objects in your ComboBox's DataTemplate with the content bound to a PriorityBinding. The lower priority would produce a TextBlock using the default font, and the higher priority would be an IsAsync binding that would create a GlyphRun with the appropriate parameters, call BuildGeometry() on it, and return the Geometry inside a Path object. The created Geometry objects can be cached and returned again for future accesses to the same font.
The result of this will be that items will initially appear in the default font, and render into the styled font as soon as the fonts can be loaded and their geometry created. Note that this can be combined with code that prefills your cache in a separate thread.
The code for Idea 2 would look something like this:
Where MyFontObjets would be a IEnumerable of objects something like this:
Note that the Geometry objects in the cache could be saved to disk by converting them to PathGeometry and thence to strings in the PathGeometry mini-language. This would allow the font geometry cache to be filled using a single file read & parse, so the only time you would see any delay was when you first ran the app, or when you ran it with a large number of new fonts.
我的解决方案是不提前渲染所有字体,通过使用字体列表的虚拟化面板,您将只加载适合屏幕的字体,它会减慢第一次滚动的速度,但用户几乎不会注意到。
看看http://www.bennedik。 de/2007/10/wpf-fast-font-drop-down-list.html
顺便说一句,如果您使用与 VirtualizingStackPanel 的组合,则必须在 DataTemplate 内设置 TextBlock 元素的宽度,否则下拉菜单的宽度会在滚动过程中发生变化。
My solution is to not render all the fonts in advance, by using a virtualized panel for teh font list you will only load the fonts that fit into the screen, it will slow down scrolling for the first time but its almost unnoticeable by the user.
look at http://www.bennedik.de/2007/10/wpf-fast-font-drop-down-list.html
BTW, if you use a combo with a VirtualizingStackPanel you will have to set the width of the TextBlock element inside the DataTemplate, otherwise the dropdown width will change during scrolling.