BlackWaspTM

This web site uses cookies. By using the site you accept the cookie policy.This message is for compliance with the UK ICO law.

Windows Presentation Foundation
.NET 4.0+

WPF Brushes - Tiled Visuals

The one hundred and thirty-ninth part of the Windows Presentation Foundation Fundamentals tutorial examines the second of the tile brushes. The VisualBrush class renders a Visual as a brush, which can generate interesting effect.

Tile Brushes

In the previous article we looked at the first of three brush classes that inherit from TileBrush. These brushes are used to fill an area with a tiled image. The first, ImageBrush, used a bitmap image as the tiled picture. The second, VisualBrush, can render any item that is derived from the Visual class as the tile.

VisualBrush can be used in two ways. Firstly, you can create a Visual specifically for the brush. This is rendered separately to the normal layout system before being applied. Although it can include user input controls, the resultant image is not interactive.

The second way you can use VisualBrush is with a pre-existing Visual. For example, you could include a TextBox within a window and bind a VisualBrush to that control. In this situation the visual is within the standard WPF layout system so the brush updates to match the text box. This makes VisualBrushes useful for special effects, such as reflections.

Using Standalone Visuals

To demonstrate the use of a visual brush we need a sample solution. Create a new WPF application in Visual Studio named, "VisualBrushDemo". Once loaded, replace the XAML in the main window with the following code:

<Window x:Class="VisualBrushDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Brush Demo" Height="200" Width="200">
    <Grid>
        <Ellipse>
            <Ellipse.Fill>
                <VisualBrush TileMode="FlipXY" Viewport="0,0 0.2,0.2">
                    <VisualBrush.Visual>
                        <Button>Test</Button>
                    </VisualBrush.Visual>
                </VisualBrush>
            </Ellipse.Fill>
        </Ellipse>
    </Grid>
</Window>

The above creates a window containing an Ellipse. The ellipse is filled using a VisualBrush. Note that the visual, this time a Button, is defined in the brush's Visual property. The example also uses the TileMode and Viewport properties of the TileBrush base class to tile the button image and flip it between rows and columns.

Run the program to see the results. Move the mouse pointer over the filled area to see that it does not react to user input.

VisualBrush demo window

A standalone Visual does not have a parent control that can define its size. This means that the button in the example renders at a default size, based upon its content. This can lead to unexpected results with some visuals, so it is usually a good idea to specify the size of the visual. This can be especially important when using a layout control with children.

Let's apply a size to the button to see the results. Update the brush's XAML, as follows:

<Button Width="50" Height="40">Test<Button>

The new size determines the overall layout of the visual within the tile. It does not set the size of the tile; this is controlled by the Viewport value and the stretch mode.

VisualBrush with standalone visual with size applied

Using Existing Visuals

Linking a brush's visual to an existing user interface element means that changes to the control are repeated in the brush. The user cannot interact with the visual via the brush directly but can affect the image displayed. In the final example in this article we'll use this method to add a reflection effect to a text box.

Replace the XAML of the entire window, as follows:

<Window x:Class="VisualBrushDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Brush Demo" Height="100" Width="200">
    <StackPanel>
        <TextBox Name="MyTextBox" Margin="10 10 20 0" Height="22" Background="PaleGreen" />
        <Rectangle Margin="10 0 20 0" Height="22" Opacity="0.3">
            <Rectangle.RenderTransform>
                <TransformGroup>
                    <ScaleTransform CenterY="11" ScaleY="-1"/>
                    <SkewTransform AngleX="15"/>
                </TransformGroup>
            </Rectangle.RenderTransform>

            <Rectangle.Fill>
                <VisualBrush Visual="{Binding ElementName=MyTextBox}" />
            </Rectangle.Fill>
        </Rectangle>
    </StackPanel>
</Window>

In the XAML, the text box is defined first. The VisualBrush's Visual property is bound to it using the control's name but no path. This means that the entire control is connected to the brush. This time the brush is applied to a Rectangle that is a similar size to the text box but that is skewed, flipped and made partially transparent to suggest a reflection. NB: We'll look at the skew and scale transformations later in the tutorial.

Run the program and enter some text into the text box. You will see that the rectangle's filled area updates to match the input control.

VisualBrush with bound visual

27 February 2015