Silverlight Layout System
This topic describes the Silverlight layout system. Understanding how the plug-in is positioned in an HTML page and how and when layout calculations occur inside the plug-in is essential in crafting great-looking, high-performance user interfaces.
This topic contains the following sections.
- The Silverlight Plug-in Position and Dimensions
- The Layout System
- Element Bounding Boxes
- Measuring and Arranging Children
- Panel Elements and Custom Layout Behaviors
- Window Resizing
- Related Topics
The Silverlight Plug-in Position and Dimensions
The Silverlight plug-in defines the area that the Silverlight-based application is displayed in. You embed the plug-in in a host HTML page; you can either position the plug-in somewhere inline in the HTML page display or have the plug-in take up the entire HTML page. Because of this, there are two frames of reference when positioning Silverlight objects:
Within the plug-in: Position objects on the Silverlight surface within the plug-in’s bounding box. Most of the layout overviews describe this type of positioning.
The Layout System
The term layout describes the process of sizing and positioning objects in your Silverlight-based application. To position visual objects, you must put them in a Panel or other container object. The parent Panel has defined layout behavior that determines how the members of a Panel element's Children collection are drawn onscreen. This is an intensive process, and the larger the Children collection, the greater the number of calculations made. Complexity can also be introduced based upon the layout behavior defined by the Panel element that owns the collection. A relatively simple layout such as Canvas can yield excellent performance when a more complex Panel such as Grid is not required.
Each time a child UIElement changes its position, it has the potential to trigger a new pass by the layout system. It's important to understand the events that can invoke the layout system, because unnecessary invocation can lead to poor application performance.
At its simplest, layout is a recursive system that leads to an element being sized, positioned, and drawn onscreen. The layout system completes two passes for each member of the Children collection, first a Measure pass and then an Arrange pass. The Measure pass is where the desired size of each child element is determined. The Arrange pass is where each child element's size and position is finalized.
When referring to the layout of an element, it is more precise to refer to the layout of that element's bounding box. For more information, see Element Bounding Boxes later in this topic.
To override the default Panel layout behavior, each type of Panel provides its own MeasureOverride and ArrangeOverride methods in order to achieve its own specific layout behavior. This is the series of events that occurs whenever the layout system is invoked:
Each child UIElement is measured.
Content is arranged after all children have been measured.
The Children collection is drawn to the screen.
This process, and the means by which it is invoked, are defined in greater detail in the following sections.
Element Bounding Boxes
It is important to understand that a bounding box surrounds all elements in a Silverlight-based application. This abstraction assists in comprehending the behavior of the layout system. When the layout system positions any FrameworkElement, it is really positioning a rectangle, or layout slot, that contains that element.
The LayoutInformation class is exposed to return the geometric boundaries of an element's layout slot and visible region. The size of the layout slot is determined by the system, by calculating the available screen space, the size of any constraints, layout-specific properties such as margin and padding, and the individual behavior of the parent Panel element. From this data, the system is able to calculate the position of all the children of a given Panel. It is important to remember that sizing characteristics defined on the parent element (such as a Border) affect its children.
The following illustration shows the dimensions of a parent panel, its child element, and the layout slot that contains the child.
You can see that the allocated area for the child is actually much larger than the child element. It is up to the parent container to determine the size of the layout slot for each child. The parent can allocate more or less space than the child requests. You can obtain the dimensions of the layout slot by calling GetLayoutSlot. The parent then positions the child inside its layout slot based on the alignment properties set on the child.
The following illustration shows a child element that is rotated and now extends beyond its assigned layout slot.
In this case, the layout system clips the child element and displays only the portion of the element that fits inside the layout slot. This visible region, outlined in red, is called the layout clip, and you can obtain its dimensions by calling GetLayoutClip. Note that GetLayoutClip returns a Geometry object, so the visible region is not necessarily a rectangle.
The bounding box around an element can change as additional elements are added to the parent container. It can shrink or expand, depending on the type and size of elements that are added.
Measuring and Arranging Children
When elements need to be rendered to the screen or an element's size changes, the layout system is invoked. The first pass of layout is the Measure pass, where the desired size of each child is determined. The second pass is the Arrange pass, where the final size of each child's bounding box size and position is determined.
In the Measure pass, the layout system tells the Panel its availableSize. This is the area that the parent is making available for the Panel to lay out its children. The Panel evaluates the native size properties of each of its children, such as Clip and Visibility.
Next, FrameworkElement properties defined on each child are processed. These properties tend to describe the sizing characteristics of the underlying UIElement, such as its Height, Width, Margin, and Style. Each of these properties can alter the space necessary to display the element. Then the Panel calls the Measure method of each of its children, passing the available size for that child. The available size can be the requested size of the child, but the parent can also choose to restrict the size of the child based on the number of elements it needs to lay out and its own availableSize.
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. Height and Width must be set, because the default is 0.
Because ActualHeight is a calculated value, you should be aware that there can 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 layout system to determine the DesiredSize of each child, which happens internally after Measure is called. This value is stored and used during the Arrange process.
In the Arrange pass, the layout system tells the Panel the finalSize that is available to it and its children. During the arrange pass, the parent Panel element evaluates the DesiredSize of the child and any additional margins that may affect the rendered size of the element and determines the bounding box for each child. The bounding box determines the dimensions of the layout slot for the child. The parent Panel then calls the Arrange method of each child, passing the Rect that sets the child's point of origin in the panel and its height and width.
All layout is relative to the parent element. If you set the point of origin to 0,0, the child element is placed in the top-left corner of the parent panel, not the top-left corner of the Silverlight plug-in.
The layout system does a final evaluation of offset properties such as margin and alignment and places the child within its layout slot. The child does not need to (and frequently won't) fill the entire allocated space. Control is then returned to the parent Panel, and the layout process is complete.
Panel Elements and Custom Layout Behaviors
Silverlight includes a derived suite of Panel elements that enable many complex layouts. Common scenarios, such as stacking elements, can easily be achieved using the StackPanel element, while more complex layouts are possible using a Grid.
The following table summarizes the available layout elements.
Defines an area within which you can explicitly position child elements by coordinates relative to the Canvas area.
Defines a flexible grid area consisting of columns and rows.
Arranges child elements into a single line that can be oriented horizontally or vertically.
Each of these layout containers takes into consideration different properties that may affect how children are arranged. A few of the common ones are shown in the following table.
Create space between an object and its layout slot.
Position an object within its layout slot.
Position an object on top of another when they overlap.
For scenarios that require application layout that is not possible using any of the predefined Panel elements, custom layout behaviors can be achieved by inheriting from Panel and overriding the default measure and arrange behavior by using the MeasureOverride and ArrangeOverride methods. For more information, see Custom Panels.
Although absolute positioning of objects by using a Canvas is useful in some scenarios, it is typically a bad strategy in a browser window that will vary in size. Absolute positioning does not allow your objects to reflow on the page in response to browser window resizing; instead, objects remain positioned at their specified pixel positions.
StackPanel and Grid allow for reflow of content. The Grid object is the root element used by the Visual Studio Silverlight template. Although the Grid is more complex to use than other Panel objects, it enables reflow of content and is flexible enough for you to create a variety of object layouts.
To get the best window resizing behavior (in addition to using Panel objects to position child objects), it is generally best to leave the DOM width and height properties at 100% and exclude any width or height declarations from the root element of your XAML file or the layout root element. For example, in the following XAML, neither the root element nor the layout element has a width or height defined.
<UserControl x:Name="RootElement" x:Class="WindowResizingSample.Page" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <Grid x:Name="LayoutRoot" Background="White"> </Grid> </UserControl>