In what order are Panels the most efficient in terms of render time and performance?
There are many times when more than one panel would suitable for the layout I want, however I know there is a difference in render times for different panel types.
For example, MSDN states that
A relatively simple
Panel
, such asCanvas
, can have significantly better performance than a more complexPanel
, such asGrid
.
So in terms of render time and performance, in what order are WPF panels the most efficient?
WPF Panels:
Canvas
DockPanel
Grid
UniformGrid
StackPanel
WrapPanel
-
VirtualizingPanel
/VirtualizingStackPanel
I'm fairly sure I saw a list of this somewhere online, but I can't find it now.
The ideal answer I am looking for would provide me a list of panels in the order that they would render fastest. I understand the number of children is a big factor in how efficient the panels are, so for the sake of this question, assume each panel only has a Label
/TextBox
pair.
In addition, I would like a list of exceptions, such as specific panels which perform better than others based on certain conditions.
Update
To summarize based on the accepted answer below, the panel performance is based on the number and layout of child items, however in general the list from fastest to slowest is:
Canvas
StackPanel
WrapPanel
DockPanel
Grid
In addition, a VirtualizingPanel
/ VirtualizingStackPanel
should always be used if there are a lot of items that don't always fit on the screen.
I'd highly recommend you read the accepted answer below for more details before just picking an item from this list.
I think it is more concise and understandable to describe the performance characteristics of each panel than it is to try to give an absolute relative performance comparison.
WPF makes two passes when rendering content: Measure and Arrange. Each panel has different performance characteristics for each of these two passes.
The performance of the measure pass is most affected by the ability of a panel to accommodate stretching using alignments (or Auto in the case of the Grid
) and then the number of children which are stretched or auto-sized. The performance of the Arrange pass is affected by the complexity of the interaction between layout location of different children and then of course the number of children.
At times the given panels don't easily lend themselves to the needed layout. I created a control that needed an arbitrary number of items to each be positioned at a certain percentage of the available space. None of the default controls do this. Attempting to make them do this (via binding to the actual size of the parent) results in horrible performance. I created a layout panel based on the Canvas which achieved my desired result with minimal work (I copied the source for the canvas and modified around 20 lines of it).
Available Panels:
-
Canvas
Defines an area within which you can explicitly position child elements by coordinates relative to the Canvas area.
The Canvas has the best performance of all the panels for the arrange pass since each item is statically assigned a location. The measure pass also has excellent performance since there is no concept of stretching in this panel; each child simply uses its native size.
-
DockPanel
Defines an area within which you can arrange child elements either horizontally or vertically, relative to each other.
The Dockpanel has a very simple layout scheme where items are added one by one relative to the previous item added. By default either the height or width is determined by the item's native size (based on Top/Bottom vs Left/Right respectively) and the other direction is determined by the
Dock
property if the width or height is undefined. Medium to fast measure pass and medium to fast arrangement pass. -
Grid
Defines a flexible grid area that consists of columns and rows.
This can be the most performance intensive panel if proportional sizing or auto sizing is used. Calculating child item size can be a complex combination of the native size of the item and the layout specified by the grid. Layout is also the most complicated of all the panels. Slow to medium performance for the measure pass and slow to medium performance for the arrangement pass.
-
StackPanel
Arranges child elements into a single line that can be oriented horizontally or vertically.
The StackPanel measures its children using either native or relative sizing in the opposite direction from its orientation and native sizing in the direction of its orientation (alignment does nothing in this direction). This makes it a mid-level performer in this area. The Arrangement pass is simply, just laying out the items in order. Probably the second-best performance for this pass. Medium performance for the measure pass and fast performance for the layout pass.
-
VirtualizingPanel
Provides a framework for Panel elements that virtualize their child data collection. This is an abstract class.
A base class for implementing your own virtualizing panel. Only loads visible items to prevent unneeded use of memory and processor. MUCH more performant for sets of items. Probably slightly less performant for items that fit on the screen due to the bounds checking. The SDK only provides one subclass of this, the
VirtualizingStackPanel
. -
WrapPanel
Positions child elements in sequential position from left to right, breaking content to the next line at the edge of the containing box. Subsequent ordering occurs sequentially from top to bottom or right to left, depending on the value of the Orientation property.
The measure pass is a somewhat complex pass where the largest item for a particular row determines the height of the row and then each item on that row either uses its native height (if it has one) or the height of the row. The layout pass is simple, putting each item one after the other on a row and then continuing onto the next row when there is not enough room for the next item. Medium performance measure pass. Medium to fast performance for the arrangement pass.
References:
Use the Most Efficient Panel where Possible
The complexity of the layout process is directly based on the layout behavior of the Panel-derived elements you use. For example, a Grid or StackPanel control provides much more functionality than a Canvas control. The price for this greater increase in functionality is a greater increase in performance costs. However, if you do not require the functionality that a Grid control provides, you should use the less costly alternatives, such as a Canvas or a custom panel.
From Optimizing Performance: Layout and Design
The layout system completes two passes for each member of the Children collection, a measure pass and an arrange pass. Each child Panel provides its own MeasureOverride and ArrangeOverride methods to achieve its own specific layout behavior.
During the measure pass, each member of the Children collection is evaluated. The process begins with a call to the Measure method. This method is called within the implementation of the parent Panel element, and does not have to be called explicitly for layout to occur.
First, native size properties of the UIElement are evaluated, such as Clip and Visibility. This generates a value named constraintSize that is passed to MeasureCore.
Secondly, framework properties defined on FrameworkElement are processed, which affects the value of constraintSize. These properties generally describe the sizing characteristics of the underlying UIElement, such as its Height, Width, Margin, and Style. Each of these properties can change the space that is necessary to display the element. MeasureOverride is then called with constraintSize as a parameter.
Note There is a difference between the properties of Height and Width and ActualHeight and ActualWidth. For example, the ActualHeight property is a calculated value based on other height inputs and the layout system. The value is set by the layout system itself, based on an actual rendering pass, and may therefore lag slightly behind the set value of properties, such as Height, that are the basis of the input change. Because ActualHeight is a calculated value, you should be aware that there could be multiple or incremental reported changes to it as a result of various operations by the layout system. The layout system may be calculating required measure space for child elements, constraints by the parent element, and so on. The ultimate goal of the measure pass is for the child to determine its DesiredSize, which occurs during the MeasureCore call. The DesiredSize value is stored by Measure for use during the content arrange pass.
The arrange pass begins with a call to the Arrange method. During the arrange pass, the parent Panel element generates a rectangle that represents the bounds of the child. This value is passed to the ArrangeCore method for processing.
The ArrangeCore method evaluates the DesiredSize of the child and evaluates any additional margins that may affect the rendered size of the element. ArrangeCore generates an arrangeSize, which is passed to the ArrangeOverride method of the Panel as a parameter. ArrangeOverride generates the finalSize of the child. Finally, the ArrangeCore method does a final evaluation of offset properties, such as margin and alignment, and puts the child within its layout slot. The child does not have to (and frequently does not) fill the entire allocated space. Control is then returned to the parent Panel and the layout process is complete.
From Measuring and Arranging Children
Maybe this will help you.
Not only for panels but also for every application you want to make in WPF.
It concludes WPF drawing & measuring performance.
It also has a drawing test application, results, and conclusions information for different operating systems that you want to target.
The panels you mention are Layout panels so a brief overview of the layout system suggests that it's likely not going to be just a simple list of the most efficient panel but how you use the panels that have the largest effect on efficiency and performance.
LayoutSystem_Overview :
At its simplest, layout is a recursive system that leads to an element being sized, positioned, and drawn. More specifically, layout describes the process of measuring and arranging the members of a Panel element's Children collection. Layout is an intensive process. The larger the Children collection, the greater the number of calculations that must be made. Complexity can also be introduced based on the layout behavior defined by the Panel element that owns the collection. A relatively simple Panel, such as Canvas, can have significantly better performance than a more complex Panel, such as Grid.
Each time that a child UIElement changes its position, it has the potential to trigger a new pass by the layout system. Therefore, it is important to understand the events that can invoke the layout system, as unnecessary invocation can lead to poor application performance. The following describes the process that occurs when the layout system is invoked.
1. A child UIElement begins the layout process by first having its core properties measured.
2. Sizing properties defined on FrameworkElement are evaluated, such as Width, Height, and Margin.
3. Panel-specific logic is applied, such as Dock direction or stacking Orientation.
4. Content is arranged after all children have been measured.
5. The Children collection is drawn on the screen.
6. The process is invoked again if additional Children are added to the collection, a LayoutTransform is applied, or the UpdateLayout method is called.
See LayoutSystem_Measure_Arrange for more information on the measuring and arranging of children
LayoutSystem_Performance :
Layout is a recursive process. Each child element in a Children collection gets processed during each invocation of the layout system. As a result, triggering the layout system should be avoided when it is not necessary. The following considerations can help you achieve better performance.
Be aware of which property value changes will force a recursive update by the layout system.
Dependency properties whose values can cause the layout system to be initialized are marked with public flags. AffectsMeasure and AffectsArrange provide useful clues as to which property value changes will force a recursive update by the layout system. In general, any property that can affect the size of an element's bounding box should have a AffectsMeasure flag set to true. For more information, see Dependency Properties Overview.
When possible, use a RenderTransform instead of a LayoutTransform.
A LayoutTransform can be a very useful way to affect the content of a user interface (UI). However, if the effect of the transform does not have to impact the position of other elements, it is best to use a RenderTransform instead, because RenderTransform does not invoke the layout system. LayoutTransform applies its transformation and forces a recursive layout update to account for the new position of the affected element.
Avoid unnecessary calls to UpdateLayout.
The UpdateLayout method forces a recursive layout update, and is frequently not necessary. Unless you are sure that a full update is required, rely on the layout system to call this method for you.
When working with a large Children collection, consider using a VirtualizingStackPanel instead of a regular StackPanel.
By virtualizing the child collection, the VirtualizingStackPanel only keeps objects in memory that are currently within the parent's ViewPort. As a result, performance is substantially improved in most scenarios.
Optimizing Performance: Layout and Design: This article goes into detail on how to build the tree efficiently and gives a simple list of panels based on their complexity
Canvas (least complext = more efficient and better performance)
Grid
Other Panels (more complex = less efficient and worse performance)
Other performance considerations to pay attention to: Ways to improve WPF UI rendering speed
- Cache everything. Brushes, Colors, Geometries, Formatted Texts, Glyphs. (For example we have two classes: RenderTools and TextCache. Rendering process of each unit addresses to shared instance of both classes. So if two charts have the same text, its preparation is executed just once.)
- Freeze Freezable, if you are planning to use it for a long time. Especially geometries. Complex unfreezed geometries execute HitTest extremely slow.
- Choose the fastest ways of rendering of each primitive. For example, there is about 6 ways of text rendering, but the fastest is DrawingContext.DrawGlyphs.
- Enable Container Recycling. Virtualization brings a lot of performance improvements, but the containers will be disposed and re created, this is the default. But you can gain more performance by recycle containers by setting VirtualizingStackPanel.VirtualizationMode="Recycling"
- From here: There is no practical limit to the amount of nesting that your application can support, however, it is generally best to limit your application to only use those panels that are actually necessary for your desired layout. In many cases, a Grid element can be used instead of nested panels due to its flexibility as a layout container. This can increase performance in your application by keeping unnecessary elements out of the tree.