#809 – You Can Use a Brush for a Control’s Background

A control’s Background property dictates how the background of the control is rendered.  It is set to an instance of a Brush object.  The two most common types of brushes are solid color brushes (SolidColorBrush) and brushes painted with a color gradient (GradientBrush).

You can use the shortcut of specifying one of the predefined colors for the value of the Background property.  This will cause the background to be rendered with a predefined SolidColorBrush of the specified color.

    <StackPanel>
        <Label Content="Hemingway" HorizontalAlignment="Center"
               Background="LightBlue"/>
        <Label Content="Fitzgerald" HorizontalAlignment="Center"
               Background="Thistle"/>
    </StackPanel>

809-001
You can also explicitly define a brush. The example below uses a LinearGradientBrush that ranges between two colors.

        <Label Content="Hemingway and Fitgerald" HorizontalAlignment="Center"
               Padding="20,10" Margin="10">
            <Label.Background>
                <LinearGradientBrush>
                    <GradientStop Color="LightBlue" Offset="0.0"/>
                    <GradientStop Color="Thistle" Offset="1.0"/>
                </LinearGradientBrush>
            </Label.Background>
        </Label>

809-002

Advertisement

#808 – How Shape Elements Are Positioned within a Canvas

The different Shape elements (e.g. Ellipse, Line, Path, Polygon, Polyline or Rectangle) describe a shape to be drawn using an X,Y coordinate system, with X increasing from left to right and Y increasing from top to bottom.

When you add Shape elements to a Canvas, the coordinates specified for the elements are used to determine the element’s position within the coordinate space of the Canvas.  For example, a point in a shape at (0,0) would be located in the upper left corner of the Canvas.

    <Canvas Margin="10" Background="AliceBlue">
        <Polygon Points="10,10 60,60 60,100 140,80 120,40"
                 Stroke="DarkViolet" StrokeThickness="2"/>
    </Canvas>

808-001
If you set any of attached properties for positioning with the Canvas (Left, Top, Right, Bottom), these properties will be used to offset the entire shape, relative to one (or more) of the sides of the canvas.

    <Canvas Margin="10" Background="AliceBlue">
        <Polygon Canvas.Left="50" Canvas.Bottom="0"
                 Points="10,10 60,60 60,100 140,80 120,40"
                 Stroke="DarkViolet" StrokeThickness="2"/>
    </Canvas>

808-003

#807 – Setting the Position of Child Elements in a Canvas from Code

Recall that you position child elements in a Canvas panel by setting at most two out of four of the following attached properties: Left, Right, Top, Bottom.  In all cases, you set a property to a value expressed in WPF (device-independent) units, equivalent to 1/96 inch.

You set any of these four values from code using one of the following static methods of the Canvas property:

  • Canvas.SetLeft
  • Canvas.SetRight
  • Canvas.SetTop
  • Canvas.SetBottom
        // Whenever we move mouse over label, put it somewhere else
        private void Label_MouseMove(object sender, MouseEventArgs e)
        {
            Label lbl = sender as Label;
            Canvas canv = lbl.Parent as Canvas;

            Random rand = new Random();

            // Set position to random location
            Canvas.SetLeft(sender as UIElement,
                           rand.Next((int)(canv.ActualWidth - lbl.ActualWidth)));
            Canvas.SetTop(sender as UIElement,
                          rand.Next((int)(canv.ActualHeight - lbl.ActualHeight)));
        }

#806 – Setting ZIndex Values of Child Elements in a Canvas from Code

You use the Canvas.ZIndex attached property on a child element in a Canvas to indicate the relative positioning of elements, when they happen to overlap.  Elements that have higher ZIndex values will appear on top of elements having lower values.

        <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"
                Click="Button_Click"/>

806-001
As with other attached properties, you can set the value from code by using a static method of the form SetPropName.  In the case of ZIndex, you use the static Canvas.SetZIndex method, passing in a reference to child control.

private void Button_Click(object sender, RoutedEventArgs e)
{
    Canvas.SetZIndex(sender as UIElement, 5);
}

#805 – Some Examples of Transform Strings

You can represent any arbitrary matrix transform in XAML using a simple string which includes the values of the elements of the matrix used to do the transformation.  The format is: “M11, M12, M21, M22, OffsetX, OffsetY”.

You can therefore specify any of the standard transforms by also using a simple string in XAML and setting the proper matrix elements.  Here are examples of how to do each of the basic transform types using a simple string:

Scale Transforms: “ScaleX, 0.0, 0.0, ScaleY, 0.0, 0.0”

805-001

Rotation transforms: “cos(angle), sin(angle), -sin(angle), cos(angle), 0.0, 0.0”

805-002

Translation transforms: “1.0, 0.0, 0.0, 1.0, OffsetX, OffsetY”

805-003

 

Skew transforms: “1.0, tan(SkewY), tan(SkewX), 1.0, 0.0, 0.0”

805-004

 

#804 – Specifying a MatrixTransform as a Simple String

You can specify an arbitrary transform to apply to an element by using a MatrixTransform element.  Below is an example of the XAML used to do this, showing the full logical tree.

        <Label Background="LightCoral" Content="The Earth" Margin="5"
               HorizontalAlignment="Center">
            <Label.LayoutTransform>
                <MatrixTransform>
                    <MatrixTransform.Matrix>
                        <Matrix M11="1.3" M12="0.1"
                                M21="0.1" M22="1.2"
                                OffsetX="5.0" OffsetY="6.0"/>
                    </MatrixTransform.Matrix>
                </MatrixTransform>
            </Label.LayoutTransform>
        </Label>

There’s a much more concise way of specifying this transform, however.  You can take advantage of a type converter provided for the LayoutTransform or RenderTransform properties, allowing you to specify the Matrix element for the transform as a simple string.  The string has the format M11,M12,M21,M22,OffsetX,OffsetY.  So we can simplify the above XAML to the following:

        <Label Background="LightCoral" Content="The Earth" Margin="5"
               HorizontalAlignment="Center"
               LayoutTransform="1.3,0.1,0.1,1.2,5.0,6.0"/>

#803 – Specifying an Arbitrary Transform with a MatrixTransform

You can transform user interface elements using the ScaleTransformRotateTransformTranslateTransform and SkewTransform objects.  Each of these transforms maps to a 3 x 3 transformation matrix that uses homogeneous coordinates to transform the element.

You can also specify any arbitrary transformation matrix directly, using the Matrix property of a MatrixTransform object.  The Matrix property is set to a Matrix struct, containing the following properties: M11, M12, M21, M22, OffsetX, and OffsetY.  This results in the transformation matrix:

803-001

        <Label Background="LightCoral" Content="The Earth" Margin="5" HorizontalAlignment="Center">
            <Label.LayoutTransform>
                <MatrixTransform>
                    <MatrixTransform.Matrix>
                        <Matrix M11="1.3" M12="0.1" M21="0.1" M22="1.2" OffsetX="5.0" OffsetY="6.0"/>
                    </MatrixTransform.Matrix>
                </MatrixTransform>
            </Label.LayoutTransform>
        </Label>

803-002

#802 – Transforms Do Not Affect an Element’s Margins

When you apply a 2D transform to a user interface element, the transform impacts only the element and everything inside of the element.  It therefore does not change the element’s margins.

In the example below, we have a Label element that has a margin of 5 separating it from its parent Border.  Notice that when we scale the second instance of the Label, it still retains the same margin.

    <StackPanel>
        <Border BorderBrush="Black" BorderThickness="3" HorizontalAlignment="Center">
            <Label Background="LightCoral" Content="Scale Me" Margin="5"/>
        </Border>
        <Border BorderBrush="Black" BorderThickness="3" HorizontalAlignment="Center">
            <Label Background="LightCoral" Content="Scale Me" Margin="5">
                <Label.LayoutTransform>
                    <ScaleTransform ScaleX="1.5"/>
                </Label.LayoutTransform>
            </Label>
        </Border>
    </StackPanel>

802-001

#801 – Creating a Mirror Image Using a RenderTransform

You can flip an object horizontally, so that you get a mirror image, using a ScaleTransform with the ScaleX value of -1.  If you use a LayoutTransform, the object will be layed out as intended after doing the transformation.

You might, however, want to do a transform to get a mirror image only after laying everything out.  To do this, you use a RenderTransform.  You still set the ScaleX property to -1, but you also need to set the RenderTransformOrigin to be located in the middle of the object being transformed.

    <StackPanel RenderTransformOrigin="0.5,0.5">
        <StackPanel.RenderTransform>
            <ScaleTransform ScaleX="-1"/>
        </StackPanel.RenderTransform>

        <Label Content="Earthquake hits San Francisco!" Margin="5"
               FontSize="16" FontFamily="Constantia" />
        <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
            <DatePicker SelectedDate="4/18/1906"/>
            <Label Content="Horrible!" FontWeight="Bold"/>
        </StackPanel>
        <Button Content="Donate $$ Now" HorizontalAlignment="Center"
                Padding="10,5" Margin="15"/>
    </StackPanel>

801-001

#800 – Transforms Do Not Affect ActualWidth and ActualHeight

Transforms do not change the values of the original element’s dimensions, as reported by the ActualWidth and ActualHeight properties.  This is true for both LayoutTransforms and RenderTransforms.

    <StackPanel>
        <Button Name="btn1" Content="Apollo" HorizontalAlignment="Center"
                Margin="5"/>

        <Button Name="btn2" Content="Apollo" HorizontalAlignment="Center"
                Margin="5">
            <Button.RenderTransform>
                <ScaleTransform ScaleX="1.5" ScaleY="2.0"/>
            </Button.RenderTransform>
        </Button>

        <Button Name="btn3" Content="Apollo" HorizontalAlignment="Center"
                Margin="5">
            <Button.LayoutTransform>
                <ScaleTransform ScaleX="1.5" ScaleY="2.0"/>
            </Button.LayoutTransform>
        </Button>

        <Button Content="Debug" Click="Button_Click" HorizontalAlignment="Center"
                Margin="10"/>
    </StackPanel>

800-001
Notice that when we inspect the elements in the debugger, they all have identical values for ActualWidth and ActualHeight.
800-002