Canvas Control In WPF

Introduction


We are familiar with a canvas used in a painting, it is used as a surface for oil painting.
 
Artists can paint in any direction at any point, he can even overlap some of his art.
 
The artist has complete control over the canvas. It is up to the artist to decide where to put items on the canvas.

A canvas looks something like this. (The white paper on the board)
 
Canvas Control In WPF
 
WPF canvas panel follows the same rules as per the real-life canvas, it gives complete control to the developer.

It allows child controls to be overlapped or to be placed in any direction as per the developer's wish.

Canvas has 4 attached properties that specify the position of child controls.

Left, Right, Top, Bottom

Canvas.Left="10"
Canvas.Top="10"

Here, 10 specifies the margin from that coordinate, Canvas.left = "10", that control will be positioned on the left side by keeping a margin of 10

Let's see a basic example.

We will draw some basic 2D shapes, and see how to place them in the canvas panel.

Shapes in the following order:
  1. Ellipse
  2. Rectangle
  3. Rectangle with curved edges
  4. Path
  5. Path with heart shape
Order is very important in canvas because canvas overlaps last control over the previous ones, meaning the 2nd Rectangle will be overlapped on the 1st Ellipse

Lets's see how the code will look:
  1. <Window x:Class="A.MainWindow"    
  2.         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"    
  3.         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"    
  4.         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"    
  5.         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"    
  6.         mc:Ignorable="d"    
  7.         Title="MainWindow" Height="320" Width="320">    
  8.     <Window.Resources>    
  9.         <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>    
  10.     </Window.Resources>    

  11.    <Canvas x:Name="CanvasPanel"    
  12.             Background="LightGray">    
  13.         <Ellipse x:Name="TwoDEllipse"        
  14.             Width = "100"         
  15.             Height = "100"         
  16.             Stroke="Black"         
  17.             Margin="10 0 0 0"        
  18.             StrokeThickness="1"    
  19.             Canvas.Left="0"    
  20.             Canvas.Top="18">    
  21.             <Ellipse.Fill>    
  22.                 <RadialGradientBrush>    
  23.                     <GradientStop Offset = "0" Color = "AliceBlue"/>    
  24.                     <GradientStop Offset = "1" Color = "LightBlue"/>    
  25.                     <GradientStop Offset = "2" Color = "DarkBlue"/>    
  26.                 </RadialGradientBrush>    
  27.             </Ellipse.Fill>    
  28.         </Ellipse>    
  29.     
  30.         <Rectangle x:Name="TwoDRectangle"        
  31.              Width="75"         
  32.              Height="75"         
  33.              Margin = "10 0 0 0"        
  34.              Stroke="Black"         
  35.              StrokeThickness="1"    
  36.              Canvas.Left="50"    
  37.              Canvas.Top="65">    
  38.             <Rectangle.Fill>    
  39.                 <RadialGradientBrush>    
  40.                     <GradientStop Offset = "0" Color = "#f1ba82"/>    
  41.                     <GradientStop Offset = "1" Color = "Coral"/>    
  42.                     <GradientStop Offset = "2" Color = "Coral"/>    
  43.                 </RadialGradientBrush>    
  44.             </Rectangle.Fill>    
  45.         </Rectangle>    
  46.     
  47.         <Rectangle x:Name="TwoDRectangle2"        
  48.              Width="75"         
  49.              Height="75"         
  50.              Margin = "10 0 0 0"        
  51.              Stroke="Black"         
  52.              StrokeThickness="1"        
  53.              RadiusX="10"        
  54.              RadiusY="10"    
  55.              Canvas.Left="90"    
  56.              Canvas.Top="100">    
  57.             <Rectangle.Fill>    
  58.                 <RadialGradientBrush>    
  59.                     <GradientStop Offset = "0" Color = "Coral"/>    
  60.                     <GradientStop Offset = "1" Color = "#ff3f33"/>    
  61.                     <GradientStop Offset = "2" Color = "#ff5733"/>    
  62.                 </RadialGradientBrush>    
  63.             </Rectangle.Fill>    
  64.         </Rectangle>    
  65.     
  66.         <Path x:Name="TwoDPath"        
  67.                   Margin = "10 0 0 0"        
  68.                   Height = "80"        
  69.                   Width="80"        
  70.                   Stroke="Black"         
  71.                   StrokeThickness="1"        
  72.                   Stretch = "Fill"    
  73.              Canvas.Left="124"    
  74.              Canvas.Top="134">    
  75.             <Path.Data>    
  76.                 <PathGeometry x:Name="PathGeoMetry">    
  77.                     <PathFigure StartPoint = "50,0" IsClosed = "True">    
  78.                         <LineSegment Point = "100,50"/>    
  79.                         <LineSegment Point = "50,100"/>    
  80.                         <LineSegment Point = "0,50"/>    
  81.                     </PathFigure>    
  82.                 </PathGeometry>    
  83.             </Path.Data>    
  84.             <Path.Fill>    
  85.                 <RadialGradientBrush>    
  86.                     <GradientStop Offset = "0" Color = "#e8e670"/>    
  87.                     <GradientStop Offset = "1" Color = "#eda619"/>    
  88.                     <GradientStop Offset = "2" Color = "#edea19"/>    
  89.                 </RadialGradientBrush>    
  90.             </Path.Fill>    
  91.         </Path>    
  92.     
  93.         <Path x:Name="PathHeart"     
  94.             Data="M 241,200         
  95.                   A 20,20 0 0 0 200,240        
  96.                   C 210,250 240,270 240,270        
  97.                   C 240,270 260,260 280,240        
  98.                   A 20,20 0 0 0 239,200"       
  99.               Stroke="Black"     
  100.               StrokeThickness="1"       
  101.               Canvas.Right="35"    
  102.               Canvas.Bottom="30"    
  103.                   Visibility="{Binding IsButtonClicked, Converter={StaticResource BooleanToVisibilityConverter}}">    
  104.             <Path.Fill>    
  105.                 <RadialGradientBrush>    
  106.                     <GradientStop Offset = "0" Color = "#e88270"/>    
  107.                     <GradientStop Offset = "1" Color = "#ee3514"/>    
  108.                     <GradientStop Offset = "2" Color = "#ee1414"/>    
  109.                 </RadialGradientBrush>    
  110.             </Path.Fill>    
  111.         </Path>    
  112.     </Canvas>    
  113. </Window>    
And this is how the output looks:
 
Canvas Control In WPF
 
Here, we have limited shapes so we can manually put control (which we want to display on top) at the end of the XAML.

It gets really messy when it has more than 20 or 30 shapes.

To overcome this problem, the canvas panel has a property named Z Index. Control with the higher z index overlaps the one with a lower z index.

Note
2 controls can have the same z index, but then last defined control will overlap the previous one.

Let's make changes in our example set Panel.ZIndex of the Rectangle & Path to 2 and this 2 will overlap our centered shape, which is a cornered edge rectangle. To achieve that, set its Panel.ZIndex = 1.
 
So now, the order for ZIndex is 0 - 2 - 1 - 2 - 0. why 0? Because by default, ZIndex is set to 0.
  1. <Rectangle x:Name="TwoDRectangle"        
  2.            Width="75"         
  3.            Height="75"         
  4.            Margin = "10 0 0 0"        
  5.            Stroke="Black"         
  6.            StrokeThickness="1"    
  7.            Canvas.Left="50"    
  8.            Canvas.Top="65"    
  9.            Panel.ZIndex="2">    
  10.           <Rectangle.Fill>    
  11.               <RadialGradientBrush>    
  12.                   <GradientStop Offset = "0" Color = "#f1ba82"/>    
  13.                   <GradientStop Offset = "1" Color = "Coral"/>    
  14.                   <GradientStop Offset = "2" Color = "Coral"/>    
  15.               </RadialGradientBrush>    
  16.           </Rectangle.Fill>    
  17.       </Rectangle>    
  18.     
  19.       <Rectangle x:Name="TwoDRectangle2"        
  20.            Width="75"         
  21.            Height="75"         
  22.            Margin = "10 0 0 0"        
  23.            Stroke="Black"         
  24.            StrokeThickness="1"        
  25.            RadiusX="10"        
  26.            RadiusY="10"    
  27.            Canvas.Left="90"    
  28.            Canvas.Top="100"    
  29.            Panel.ZIndex="1">    
  30.           <Rectangle.Fill>    
  31.               <RadialGradientBrush>    
  32.                   <GradientStop Offset = "0" Color = "Coral"/>    
  33.                   <GradientStop Offset = "1" Color = "#ff3f33"/>    
  34.                   <GradientStop Offset = "2" Color = "#ff5733"/>    
  35.               </RadialGradientBrush>    
  36.           </Rectangle.Fill>    
  37.       </Rectangle>    
  38.     
  39.       <Path x:Name="TwoDPath"        
  40.                 Margin = "10 0 0 0"        
  41.                 Height = "80"        
  42.                 Width="80"        
  43.                 Stroke="Black"         
  44.                 StrokeThickness="1"        
  45.                 Stretch = "Fill"    
  46.            Canvas.Left="124"    
  47.            Canvas.Top="134"    
  48.             Panel.ZIndex="2">    
  49.           <Path.Data>    
  50.               <PathGeometry x:Name="PathGeoMetry">    
  51.                   <PathFigure StartPoint = "50,0" IsClosed = "True">    
  52.                       <LineSegment Point = "100,50"/>    
  53.                       <LineSegment Point = "50,100"/>    
  54.                       <LineSegment Point = "0,50"/>    
  55.                   </PathFigure>    
  56.               </PathGeometry>    
  57.           </Path.Data>    
  58.           <Path.Fill>    
  59.               <RadialGradientBrush>    
  60.                   <GradientStop Offset = "0" Color = "#e8e670"/>    
  61.                   <GradientStop Offset = "1" Color = "#eda619"/>    
  62.                   <GradientStop Offset = "2" Color = "#edea19"/>    
  63.               </RadialGradientBrush>    
  64.           </Path.Fill>    
  65.       </Path>    
Now let's check out the output:
 
Canvas Control In WPF

Here, we can see our second and fourth control has overlapped on the third control as ZIndex for third is 1 where ZIndex for the other two is 2.
 

Conclusion

 
In this article, we learned how to use a Canvas panel and the properties used to position child control.
 
Canvas panel is the simplest amongst other panels in WPF. It is famous because of its flexibility & it is used with shapes or animations.
 
I hope you have gained some insight into Canvas panels through this article.
 
If you have any queries or just want to connect, meet me @
As always, Happy Coding!