Why is Wpf's DrawingContext.DrawText so expensive?

后端 未结 3 1039

In Wpf (4.0) my listbox (using a VirtualizingStackPanel) contains 500 items. Each item is of a custom Type

class Page : FrameworkElement
...
protected over         


        
3条回答
  •  一个人的身影
    2020-12-31 14:24

    A big contributor is the fact(based on my experience with GlyphRun which I think gets used behind the scenes) that it uses at least 2 dictionary look-ups per character to get the glyph index and width. One hack I used in my project was I figured out the offset between the ASCII value and the glyph index for alphanumeric characters for the font I was using. I then used that to calculate the glyph indexes for each character rather than doing the dictionary look up. That gave me a decent speed up. Also the fact that I could reuse the glyph run moving it around with a translate transform without recalculating everything or those dictionary lookups. The system can't do this hack on it's own because it is not generic enough to be used in every case. I imagine a similar hack could be done for other fonts. I only tested with Arial,other fonts could be indexed differently. May be able to go even faster with a mono-spaced font since you may be able to assume the glyph widths would all be the same and only do one look up rather than one per character, but I haven't tested this.

    The other slow down contributor is this little code, I haven't figured out how to hack it yet. typeface.TryGetGlyphTypeface(out glyphTypeface);

    Here is my code for my alphanumeric Arial hack(compatibility with other characters unknown)

    public  GlyphRun CreateGlyphRun(string text,double size)
        {
            Typeface typeface = new Typeface("Arial");
            GlyphTypeface glyphTypeface;
            if (!typeface.TryGetGlyphTypeface(out glyphTypeface))
                throw new InvalidOperationException("No glyphtypeface found");          
    
            ushort[] glyphIndexes = new ushort[text.Length];
            double[] advanceWidths = new double[text.Length];
    
            for (int n = 0; n < text.Length; n++) {
                ushort glyphIndex = (ushort)(text[n] - 29);
                glyphIndexes[n] = glyphIndex;
                advanceWidths[n] = glyphTypeface.AdvanceWidths[glyphIndex] * size;
            }
    
            Point origin = new Point(0, 0);
    
            GlyphRun glyphRun = new GlyphRun(glyphTypeface, 0, false, size, glyphIndexes, origin, advanceWidths, null, null, null,
                                             null, null, null);
            return glyphRun;
        }
    

提交回复
热议问题