Optimizing Performance: 2D Graphics and Imaging
WPF provides a wide range of 2D graphics and imaging functionality that can be optimized for your application requirements. This topic provides information about performance optimization in those areas.
Drawing and Shapes
WPF offers several layers of access to graphics and rendering services. At the top layer, Shape objects are easy to use and provide many useful features, such as layout and event handling. WPF provides a number of ready-to-use shape objects. All shape objects inherit from the Shape class. Available shape objects include Ellipse, Line, Path, Polygon, Polyline, and Rectangle.
There are four types of Drawing objects:
GeometryDrawing Draws a shape.
ImageDrawing Draws an image.
GlyphRunDrawing Draws text.
DrawingGroup Draws other drawings. Use a drawing group to combine other drawings into a single composite drawing.
The GeometryDrawing object is used to render geometry content. The Geometry class and the concrete classes that derive from it, such as CombinedGeometry, EllipseGeometry, and PathGeometry, provide a means for rendering 2D graphics and providing hit-testing and clipping support. Geometry objects can be used to define the region of a control, for example, or to define the clip region to apply to an image. Geometry objects can be simple regions, such as rectangles and circles, or composite regions created from two or more geometry objects. More complex geometric regions can be created by combining PathSegment-derived objects, such as ArcSegment, BezierSegment, and QuadraticBezierSegment.
On the surface, the Geometry class and the Shape class are similar. Both are used in the rendering of 2D graphics and both have similar concrete classes that derive from them, for example, EllipseGeometry and Ellipse. However, there are important differences between these two sets of classes. For one, the Geometry class lacks some of the functionality of the Shape class, such as the ability to draw itself. To draw a geometry object, another class such as DrawingContext, Drawing, or a Path (it is worth noting that a Path is a Shape) must be used to perform the drawing operation. Rendering properties such as fill, stroke, and the stroke thickness are on the class that draws the geometry object, while a shape object contains these properties. One way to think of this difference is that a geometry object defines a region, for example, a circle, while a shape object defines a region, defines how that region is filled and outlined, and participates in the layout system.
Since Shape objects derive from the FrameworkElement class, using them can add significantly more memory consumption in your application. If you really do not need the FrameworkElement features for your graphical content, consider using the lighter-weight Drawing objects.
The StreamGeometry object is a lightweight alternative to PathGeometry for creating geometric shapes. Use a StreamGeometry when you need to describe a complex geometry. StreamGeometry is optimized for handling many PathGeometry objects and performs better when compared to using many individual PathGeometry objects.
The following example uses attribute syntax to create a triangular StreamGeometry in XAML.
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <StackPanel> <Path Data="F0 M10,100 L100,100 100,50Z" StrokeThickness="1" Stroke="Black"/> </StackPanel> </Page>
The DrawingVisual object 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. For more information, see Using DrawingVisual Objects.
WPF imaging provides a significant improvement over the imaging capabilities in previous versions of Windows. Imaging capabilities, such as displaying a bitmap or using an image on a common control, were primarily handled by the Microsoft Windows Graphics Device Interface (GDI) or Microsoft Windows GDI+ application programming interface (API). These APIs provided baseline imaging functionality but lacked features such as support for codec extensibility and high fidelity image support. WPF Imaging APIs have been redesigned to overcome the shortcomings of GDI and GDI+ and provide a new set of APIs to display and use images within your applications.
When using images, consider the following recommendations for gaining better performance:
If your application requires you to display thumbnail images, consider creating a reduced-sized version of the image. By default, WPF loads your image and decodes it to its full size. If you only want a thumbnail version of the image, WPF unnecessary decodes the image to its full-size and then scales it down to a thumbnail size. To avoid this unnecessary overhead, you can either request WPF to decode the image to a thumbnail size, or request WPF to load a thumbnail size image.
Always decode the image to desired size and not to the default size. As mentioned above, request WPF to decode your image to a desired size and not the default full size. You will reduce not only your application's working set, but execution speed as well.
If possible, combine the images into a single image, such as a film strip composed of multiple images.
For more information, see Imaging Overview.
When animating the scale of any bitmap, the default high-quality image resampling algorithm can sometimes consume sufficient system resources to cause frame rate degradation, effectively causing animations to stutter. By setting the BitmapScalingMode property of the RenderOptions object to LowQuality, you can create a smoother animation when scaling a bitmap. LowQuality mode tells the WPF rendering engine to switch from a quality-optimized algorithm to a speed-optimized algorithm when processing images.
The following example shows how to set the BitmapScalingMode for an image object.
// Set the bitmap scaling mode for the image to render faster. RenderOptions.SetBitmapScalingMode(MyImage, BitmapScalingMode.LowQuality);
' Set the bitmap scaling mode for the image to render faster. RenderOptions.SetBitmapScalingMode(MyImage, BitmapScalingMode.LowQuality)
By default, WPF does not cache the rendered contents of TileBrush objects, such as DrawingBrush and VisualBrush. In static scenarios where the contents or use of the TileBrush in the scene aren't changing, this makes sense, since it conserves video memory. It does not make as much sense when a TileBrush with static content is used in a non-static way—for example, when a static DrawingBrush or VisualBrush is mapped to the surface of a rotating 3D object. The default behavior of WPF is to re-render the entire content of the DrawingBrush or VisualBrush for every frame, even though the content is unchanging.
The CacheInvalidationThresholdMinimum and CacheInvalidationThresholdMaximum property values are relative size values that determine when the TileBrush object should be regenerated due to changes in scale. For example, by setting the CacheInvalidationThresholdMaximum property to 2.0, the cache for the TileBrush only needs to be regenerated when its size exceeds twice the size of the current cache.
The following example shows how to use the caching hint option for a DrawingBrush.
DrawingBrush drawingBrush = new DrawingBrush(); // Set the caching hint option for the brush. RenderOptions.SetCachingHint(drawingBrush, CachingHint.Cache); // Set the minimum and maximum relative sizes for regenerating the tiled brush. // The tiled brush will be regenerated and re-cached when its size is // 0.5x or 2x of the current cached size. RenderOptions.SetCacheInvalidationThresholdMinimum(drawingBrush, 0.5); RenderOptions.SetCacheInvalidationThresholdMaximum(drawingBrush, 2.0);
Dim drawingBrush As New DrawingBrush() ' Set the caching hint option for the brush. RenderOptions.SetCachingHint(drawingBrush, CachingHint.Cache) ' Set the minimum and maximum relative sizes for regenerating the tiled brush. ' The tiled brush will be regenerated and re-cached when its size is ' 0.5x or 2x of the current cached size. RenderOptions.SetCacheInvalidationThresholdMinimum(drawingBrush, 0.5) RenderOptions.SetCacheInvalidationThresholdMaximum(drawingBrush, 2.0)