#478 – Two Out of Four Margin Values Are Used for Elements in a Canvas

When adding child elements to a Canvas panel, you can specify at most two of the four attached properties: Top, Left, Bottom, Right.  This places the child element relative to one of the four corners of the Canvas.

Child elements can have values for their Margin property, but only two of the four possible sub-values are used.  The two parts of the margin used are based on the two Canvas attached properties that are being used.

For example, if you position a child element using the Canvas.Bottom and Canvas.Left properties, then only the Bottom and Left portions of the child element’s Margin are used.  The Top and Right margins are ignored.

Margin values that are used are added to the canvas positioning properties.

<Canvas>
    <Button Content="Left=10, Margin.Left=0" Canvas.Left="10" Canvas.Top="10" Margin="0,0,0,0"/>
    <Button Content="Left=10, Margin.Left=15" Canvas.Left="10" Canvas.Top="40" Margin="15,0,0,0"/>
</Canvas>

Advertisement

#477 – Default ZIndex Value for Child Elements of a Canvas

You can set the Canvas.ZIndex attached property for a child element of the Canvas panel, to dictate the overlap behavior of child elements.  Elements with a higher ZIndex value will appear on top of elements with a lower value.

By default, all child elements of a Canvas have a ZIndex value of 0.  In this case, the Canvas lays out the child elements in the order that they exist in the Children collection (the same order in which they appear in XAML), with elements occurring later in the collection layering on top of elements that occur earlier in the collection.

More generally, any time that two elements have the same value for ZIndex, they are layered in the order in which the appear in the Children collection.


#476 – Set ZIndex Values for Child Elements of Canvas

By default, child elements of a Canvas panel will be arranged in the order that they appear in a XAML file, with later elements appearing on top of earlier elements.

You can override this behavior by specifying explicit values for the Canvas.ZIndex attached property.  An element with a higher ZIndex value will appear on top of an element with a lower value.

        <Canvas Name="canv" Grid.Row="0">
            <Button Content="1 - Lft10,Top10" Canvas.Left="10" Canvas.Top="10" Canvas.ZIndex="4"/>
            <Button Content="2 - Rt10,Top10" Canvas.Right="10" Canvas.Top="15" Canvas.ZIndex="3"/>
            <Button Content="3 - Lft10,Bott10..." Canvas.Left="15" Canvas.Bottom="15" Canvas.ZIndex="2"/>
            <Button Content="4 - Rt10,Bott10" Canvas.Right="10" Canvas.Bottom="8"  Canvas.ZIndex="1"/>
        </Canvas>

#475 – Child Elements in Canvas Can Overlap

It’s possible for child elements of a Canvas to overlap each other, depending on their position.  In the example below, the Canvas contains four Button controls, each located relative to one of the four corners of the Canvas.  As the parent window is resized, it eventually gets small enough for the child elements to overlap.

When child elements in a Canvas overlap, their order is based on the order in which they were added to the Canvas.  If the elements were all specified in XAML, the first elements listed will be at the bottom of overlapped elements and the last elements will be at the top.

    <Canvas>
        <Button Content="1 - Lft10,Top10" Canvas.Left="10" Canvas.Top="10"/>
        <Button Content="2 - Rt10,Top10" Canvas.Right="10" Canvas.Top="15"/>
        <Button Content="3 - Lft10,Bott10..." Canvas.Left="15" Canvas.Bottom="15"/>
        <Button Content="4 - Rt10,Bott10" Canvas.Right="10" Canvas.Bottom="8"/>
    </Canvas>

#473 – Positioning Child Elements in a Canvas

Child elements are position in a Canvas panel by specifying the location of the child element in WPF units.

You can position all elements by specifying values for Left and Top properties only.  This will position each element relative to the upper left corner of the container.

These child elements will then retain the same position from the upper left corner of the container as it is resized.

You can specify a child element’s position relative to any of the four corners of the container, depending on which two of the four positioning properties you specify.  Child elements will then retain their position relative to that corner as the container is resized.

  • Left/Top – upper left corner
  • Right/Top – upper right corner
  • Right/Bottom – lower right corner
  • Left/Bottom – lower bottom corner
    <Canvas>
        <Button Content="Left=10,Top=10" Canvas.Left="10" Canvas.Top="10"/>
        <Button Content="Right=10,Top=10" Canvas.Right="10" Canvas.Top="10"/>
        <Button Content="Right=10,Bottom=10" Canvas.Right="10" Canvas.Bottom="10"/>
        <Button Content="Left=10,Bottom=10" Canvas.Left="10" Canvas.Bottom="10"/>
    </Canvas>


#462 – Drawing a Better Looking GridSplitter

By default, a GridSplitter control is composed only of a Border element.  You can set the border’s thickness, color and background.

We can make the GridSplitter look a little nicer by drawing a couple horizontal lines on its surface.

We do this by overriding the default Style for the GridSplitter.

	<Window.Resources>
		<Style x:Key="GridSplitterPreviewStyle" >
			<Setter Property="Control.Template">
				<Setter.Value>
					<ControlTemplate>
						<Rectangle Fill="#80000000"/>
					</ControlTemplate>
				</Setter.Value>
			</Setter>
		</Style>
		<Style x:Key="GridSplitterStyle1" TargetType="{x:Type GridSplitter}">
			<Setter Property="Background"
                    Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
			<Setter Property="PreviewStyle" Value="{StaticResource GridSplitterPreviewStyle}"/>
			<Setter Property="Template">
				<Setter.Value>
					<ControlTemplate TargetType="{x:Type GridSplitter}">
						<Border BorderBrush="{TemplateBinding BorderBrush}"
                                BorderThickness="{TemplateBinding BorderThickness}"
                                Background="{TemplateBinding Background}"
                                CornerRadius="5">
                            <Canvas RenderOptions.EdgeMode="Aliased" UseLayoutRounding="True"
                                    Height="6" VerticalAlignment="Center"
                                    Width="50" HorizontalAlignment="Center">
                                <Line X1="0" X2="50" Y1="0" Y2="0"
                                      Stroke="White" StrokeThickness="1"/>
                                <Line X1="0" X2="50" Y1="1" Y2="1"
                                      Stroke="#A0A0A0" StrokeThickness="1"/>
                                <Line X1="0" X2="50" Y1="4" Y2="4"
                                      Stroke="White" StrokeThickness="1"/>
                                <Line X1="0" X2="50" Y1="5" Y2="5"
                                      Stroke="#A0A0A0" StrokeThickness="1"/>
                            </Canvas>
						</Border>
					</ControlTemplate>
				</Setter.Value>
			</Setter>
		</Style>
	</Window.Resources>

We also specify a gradient fill for the Background of the GridSplitter.

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition Height="Auto"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>

        <Label Content="Row 0 Col 0" Background="Azure" Grid.Row="0" Grid.Column="0" />
        <Label Content="Row 0 Col 1" Background="Lavender" Grid.Row="0" Grid.Column="1" />
        <Label Content="Row 2 Col 0" Background="Moccasin" Grid.Row="2" Grid.Column="0" />
        <Label Content="Row 2 Col 1" Background="Honeydew" Grid.Row="2" Grid.Column="1" />

        <GridSplitter Grid.Row ="1" Grid.ColumnSpan="2" Height="16"
                      VerticalAlignment="Center" HorizontalAlignment="Stretch"
                      BorderBrush="White" BorderThickness="1"
					  Style="{DynamicResource GridSplitterStyle1}">
            <GridSplitter.Background>
                <LinearGradientBrush EndPoint="0.5,0" StartPoint="0.5,1">
                    <GradientStop Color="#A0A0A0" Offset="0"/>
                    <GradientStop Color="#E5E5E5" Offset="0.15"/>
                    <GradientStop Color="#ECECEC" Offset="0.8"/>
                    <GradientStop Color="#E5E5E5" Offset="1"/>
                </LinearGradientBrush>
            </GridSplitter.Background>
        </GridSplitter>
    </Grid>

#394 – Specify Canvas Child Element Position Using Two Properties

When positioning child elements in a Canvas element, you can position the child element by specifying one or more of the properties: Left, Top, Right, Bottom.

In practice, the values of only two of these properties are ever used.  If Left and Right are specified, Right is ignored.  If Top and Bottom are specified, Bottom is ignored.

If neither Left nor Right are specified, a value of 0 is used for Left.  If neither Top nor Bottom are specified, a value of 0 is used for Top.

It’s a good idea, then, to always specify exactly two of these four properties, in any of the following combinations:

  • Left / Top
  • Left / Bottom
  • Right / Top
  • Right / Bottom

By always specifying exactly two properties, none are ignored and you never implicitly use a value of 0, but make the positioning clear by explicitly specifying both values that are to be used.

#393 – Canvas Element

The Canvas panel serves as a container for a collection of child elements and allows positioning its children using exact coordinates (in WPF Units).

You can specify the following attached properties for a child element of the Canvas, to control how the child element is positioned.

  • Left – Distance between left side of element and left side of canvas
  • Top – Distance between top side of element and top side of canvas
  • Right – Distance between right side of element and right side of canvas
  • Bottom – Distance between bottom side of element and bottom of canvas

If you don’t specify values for any of these properties for a child element, it will be positioned in the upper left corner of the Canvas.

    <Canvas>
        <Label Content="Pease Porridge Hot"/>
        <Label Content="Pease Porridge Cold" Canvas.Left="99" Canvas.Top="23" />
        <Button Content="In the Pot" Canvas.Left="55" Canvas.Top="63" />
        <TextBox Text="Nine Days Old" Canvas.Left="161" Canvas.Top="111" />
    </Canvas>