Canvas

The Canvas class enables us to explicitly position child elements using combinations of the Canvas.Top, Canvas.Left, Canvas.Bottom, and Canvas.Right Attached Properties. This is vaguely similar to the old Windows Forms system of control placement.

However, when using WPF, we don't typically layout UI controls in a Canvas. Instead, we tend to use them more for displaying shapes, constructing graphs, showing animations, or drawing applications. Take the following example:

<Canvas Width="256" Height="109" Background="Black"> 
  <Canvas.Resources> 
    <Style TargetType="{x:Type Ellipse}"> 
      <Setter Property="Width" Value="50" /> 
      <Setter Property="Height" Value="50" /> 
      <Setter Property="Stroke" Value="Black" /> 
      <Setter Property="StrokeThickness" Value="3" /> 
    </Style> 
  </Canvas.Resources> 
  <Canvas Canvas.Left="3" Canvas.Top="3" Background="Orange" 
    Width="123.5" Height="50"> 
    <Ellipse Canvas.Top="25" Canvas.Left="25" Fill="Cyan" /> 
  </Canvas> 
  <Canvas Canvas.Left="129.5" Canvas.Top="3" Background="Orange"  
    Width="123.5" Height="50" Panel.ZIndex="1" /> 
  <Canvas Canvas.Left="3" Canvas.Top="56" Background="Red" Width="250"  
    Height="50" ClipToBounds="True"> 
    <Ellipse Canvas.Top="-25" Canvas.Left="175" Fill="Lime" /> 
  </Canvas> 
  <Ellipse Canvas.Top="29.5" Canvas.Left="103" Fill="Yellow" /> 
</Canvas> 

This example demonstrates a number of important points, so let's first see the visual output of this code before discussing it:

The top-left rectangle is the output from one canvas, and the top-right and bottom ones are from two other canvas instances. They are all contained within a parent canvas element with a black background. The three inner canvases are spaced to give the effect that they each have a border. They have been declared in the order of top-left, top-right, bottom, and the last element to be declared is, the middle circle.

The left circle is being drawn in the top-left canvas and we can see where it is overlapping the canvas' apparent bottom border, which shows that it is not being clipped by its parent canvas. However, it is being clipped by the lower canvas element and this demonstrates that UI elements that are declared later will be displayed over the top of earlier declared elements.

Nevertheless, the second canvas to be declared is clipping the middle circle, which was the last declared element. This demonstrates that setting the Panel.ZIndex property on an element to any positive number will position that element above all others that have not explicitly set this property. The default value for this property is zero, so an element that has this property set to 1 will be rendered on top of all elements that have not explicitly set a value for it.

The next element to be declared is the bottom rectangle and the right circle is declared within it. Now, as this element is declared after the top canvases, you might expect that the right circle would overlap the upper-right canvas. While this would normally be the case, this won't happen with our example for two reasons.

The first, as we've just found out, is because the upper-right panel has a higher ZIndex property value than the lower panel and the second reason is because we have set the UIElement.ClipToBounds property to true, which is used by the Canvas panel to determine whether it should clip the visual content of any children that may lie outside the bounds of the panel.

This is commonly used with animations, to enable a visual to be hidden out of the panel bounds and then slid into view in reaction to some event. We can tell that the right circle has been clipped by its parent panel because we can see its apparent top border, which is outside its bounds.

The last element to be declared is the middle circle and we can see that, apart from the overlapping canvas element with the higher ZIndex property value, it overlaps all of the other elements. Note that the Canvas panel does not perform any kind of resizing on its children, so it is not typically used for generating form type UI.