How to draw graphics as efficiently as possible in WPF

后端 未结 3 684
情歌与酒
情歌与酒 2021-01-31 05:05

I am creating a tool which relies heavily on graph-node trees. The current implementation is done in Java and I\'m porting it to a generic code-base on C#, so it can be used by

相关标签:
3条回答
  • 2021-01-31 05:26

    I'd recommend reading Optimizing Performance: 2D Graphics and Imaging (dead link -- readable via Internet Archive) -

    Basically, Drawing objects will be lighter weight than Shapes, in general. This is probably what you want to use.

    0 讨论(0)
  • 2021-01-31 05:39

    Generally, better performance is obtained with lower-level services. In WPF, this means the Drawing family of objects. All you get are: Drawing, DrawingGroup, GeometryDrawing, GlyphRunDrawing, ImageDrawing, and VideoDrawing. However, they are sufficient for all needs. Using these types is very friendly with WPF because Drawing is the conceptual unit that WPF exchanges with your GPU accelerator, possibly retaining and managing it there if possible. This works because the Drawing is expressed in terms of portable vector drawing primitives.

    Once you start re-architecting your app around Drawings however, you might need some interop with your higher-level code which is still based on UIElement, FrameworkElement, etc. One thing that I haven't found built-in to WPF is a simple way to wrap a Drawing as a FrameworkElement in the lowest-overhead way possible. DrawingVisual isn't a complete solution, because it only derives from Visual--meaning it still requires a hosting element.

    The following class will host any WPF Drawing directly without using an intermediate DrawingVisual. I added support for FrameworkElement's Margin property (with no performance penalty if unused) but little else. Because of WPF's single rendering thread it's safe and easy to cache a single TranslateTransform object to implement the margin. I'd recommend that you supply only drawings which have been Frozen; in fact, in the version that I use, I have an assert to that effect in the constructor.

    public class DrawingElement : FrameworkElement
    {
        static readonly TranslateTransform tt_cache = new TranslateTransform();
    
        public DrawingElement(Drawing drawing)
        {
            this.drawing = drawing;
        }
        readonly Drawing drawing;
    
        TranslateTransform get_transform()
        {
            if (Margin.Left == 0 && Margin.Top == 0)
                return null;
            tt_cache.X = Margin.Left;
            tt_cache.Y = Margin.Top;
            return tt_cache;
        }
        protected override Size MeasureOverride(Size _)
        {
            var sz = drawing.Bounds.Size;
            return new Size
            {
                Width = sz.Width + Margin.Left + Margin.Right,
                Height = sz.Height + Margin.Top + Margin.Bottom,
            };
        }
        protected override void OnRender(DrawingContext dc)
        {
            var tt = get_transform();
            if (tt != null)
                dc.PushTransform(tt);
            dc.DrawDrawing(drawing);
            if (tt != null)
                dc.Pop();
        }
    };
    

    [edit:] This is also useful for inserting a WPF Drawing into the InlineUIContainer.Child property (i.e. using TextBlock.InlinesCollection to format the contents of the TextBlock more richly).

    0 讨论(0)
  • 2021-01-31 05:39

    the DrawingVisual seems to be a valid choice:

    The DrawingVisual is a lightweight drawing class that is used to render shapes, images, or text. This class is considered lightweight because it does not provide layout or event handling, which improves its performance. For this reason, drawings are ideal for backgrounds and clip art.

    source: Using DrawingVisual Objects

    so this seems to be absolutely what you ask, a Canvas SUPER lightweight.

    0 讨论(0)
提交回复
热议问题