Painting with Images, Drawings, and Visuals


This topic describes how to use ImageBrush, DrawingBrush, and VisualBrush objects to paint an area with an image, a Drawing, or a Visual.

To understand this topic, you should be familiar with the different types of brushes Windows Presentation Foundation (WPF) provides and their basic features. For an introduction, see the WPF Brushes Overview.

An ImageBrush paints an area with an ImageSource. The most common type of ImageSource to use with an ImageBrush is a BitmapImage, which describes a bitmap graphic. You can use a DrawingImage to paint using a Drawing object, but it is simpler to use a DrawingBrush instead. For more information about ImageSource objects, see the Imaging Overview.

To paint with an ImageBrush, create a BitmapImage and use it to load the bitmap content. Then, use the BitmapImage to set the ImageSource property of the ImageBrush. Finally, apply the ImageBrush to the object you want to paint. In Extensible Application Markup Language (XAML), you can also just set the ImageSource property of the ImageBrush with the path of the image to load.

Like all Brush objects, an ImageBrush can be used to paint objects such as shapes, panels, controls, and text. The following illustration shows some effects that can be achieved with an ImageBrush.

ImageBrush output examples
Objects painted by an ImageBrush

By default, an ImageBrush stretches its image to completely fill the area being painted, possibly distorting the image if the painted area has a different aspect ratio than the image. You can change this behavior by changing the Stretch property from its default value of Fill to None, Uniform, or UniformToFill. Because ImageBrush is a type of TileBrush, you can specify exactly how an image brush fills the output area and even create patterns. For more information about advanced TileBrush features, see the TileBrush Overview.

The following example uses an ImageBrush to paint the Background of a Canvas.

  WindowTitle="ImageBrush Example"


      Height="200" Width="300">
        <ImageBrush ImageSource="sampleImages\Waterlilies.jpg" />


Imports Microsoft.VisualBasic
Imports System
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Media
Imports System.Windows.Media.Imaging

Namespace Microsoft.Samples.BrushExamples

	Public Class ImageBrushExample
		Inherits Page

		Public Sub New()

			Dim mainPanel As New StackPanel()
			Me.Content = mainPanel

		End Sub

		Private Sub canvasBackgroundExample(ByVal mainPanel As Panel)

			Dim theImage As New BitmapImage(New Uri("sampleImages\Waterlilies.jpg", UriKind.Relative))

			Dim myImageBrush As New ImageBrush(theImage)

			Dim myCanvas As New Canvas()
			myCanvas.Width = 300
			myCanvas.Height = 200
			myCanvas.Background = myImageBrush


		End Sub

	End Class

End Namespace

A DrawingBrush enables you to paint an area with shapes, text, images, and video. Shapes inside a drawing brush may themselves be painted with a solid color, gradient, image, or even another DrawingBrush. The following illustration demonstrates some uses of a DrawingBrush.

DrawingBrush output examples
Objects painted by a DrawingBrush

A DrawingBrush paints an area with a Drawing object. A Drawing object describes visible content, such as a shape, bitmap, video, or a line of text. Different types of drawings describe different types of content. The following is a list of the different types of drawing objects.

For more information about Drawing objects, see the Drawing Objects Overview.

Like an ImageBrush, a DrawingBrush stretches its Drawing to fill its output area. You can override this behavior by changing the Stretch property from its default setting of Fill. For more information, see the Stretch property.

The following example shows how to paint an object with a drawing of three ellipses. A GeometryDrawing is used to describe the ellipses.

    <Button Content="A Button">
            <GeometryDrawing Brush="LightBlue">
                  <EllipseGeometry RadiusX="12.5" RadiusY="25" Center="25,50" />
                  <EllipseGeometry RadiusX="12.5" RadiusY="25" Center="50,50" />
                  <EllipseGeometry RadiusX="12.5" RadiusY="25" Center="75,50" />
                <Pen Thickness="1" Brush="Gray" />

			' Create a DrawingBrush.
			Dim myDrawingBrush As New DrawingBrush()

			' Create a drawing.
			Dim myGeometryDrawing As New GeometryDrawing()
			myGeometryDrawing.Brush = Brushes.LightBlue
			myGeometryDrawing.Pen = New Pen(Brushes.Gray, 1)
			Dim ellipses As New GeometryGroup()
			ellipses.Children.Add(New EllipseGeometry(New Point(25,50), 12.5, 25))
			ellipses.Children.Add(New EllipseGeometry(New Point(50,50), 12.5, 25))
			ellipses.Children.Add(New EllipseGeometry(New Point(75,50), 12.5, 25))

			myGeometryDrawing.Geometry = ellipses
			myDrawingBrush.Drawing = myGeometryDrawing

			Dim myButton As New Button()
			myButton.Content = "A Button"

			' Use the DrawingBrush to paint the button's background.
			myButton.Background = myDrawingBrush

The most versatile and powerful of all the brushes, the VisualBrush paints an area with a Visual. A Visual is a low-level graphical type that serves as the ancestor of many useful graphical components. For example, the Window, FrameworkElement, and Control classes are all types of Visual objects. Using a VisualBrush, you can paint areas with almost any Windows Presentation Foundation (WPF) graphical object.

System_CAPS_ICON_note.jpg Note

Although VisualBrush is a type of Freezable object, it cannot be frozen (made read-only) when its Visual property is set to a value other than null.

There are two ways to specify the Visual content of a VisualBrush.

When you define a new Visual for a VisualBrush and that Visual is a UIElement (such as a panel or control), the layout system runs on the UIElement and its child elements when the AutoLayoutContent property is set to true. However, the root UIElement is essentially isolated from the rest of the system: styles, and external layout can't permeate this boundary. Therefore, you should explicitly specify the size of the root UIElement, because its only parent is the VisualBrush and therefore it cannot automatically size itself to the area being painted. For more information about layout in Windows Presentation Foundation (WPF), see the Layout.

Like ImageBrush and DrawingBrush, a VisualBrush stretches its content to fill its output area. You can override this behavior by changing the Stretch property from its default setting of Fill. For more information, see the Stretch property.

In the following example, several controls and a panel are used to paint a rectangle.

    <Rectangle Width="150" Height="150" Stroke="Black" Margin="5,0,5,0">
            <StackPanel Background="White">
              <Rectangle Width="25" Height="25" Fill="Red" Margin="2" />
              <TextBlock FontSize="10pt" Margin="2">Hello, World!</TextBlock>
              <Button Margin="2">A Button</Button>

			Dim myVisualBrush As New VisualBrush()

			' Create the visual brush's contents.
			Dim myStackPanel As New StackPanel()
			myStackPanel.Background = Brushes.White

            Dim redRectangle As New Rectangle()
            With redRectangle
                .Width = 25
                .Height = 25
                .Fill = Brushes.Red
                .Margin = New Thickness(2)
            End With

            Dim someText As New TextBlock()
            Dim myFontSizeConverter As New FontSizeConverter()
            someText.FontSize = CDbl(myFontSizeConverter.ConvertFrom("10pt"))
            someText.Text = "Hello, World!"
            someText.Margin = New Thickness(2)

            Dim aButton As New Button()
            aButton.Content = "A Button"
            aButton.Margin = New Thickness(2)

            ' Use myStackPanel as myVisualBrush's content.
            myVisualBrush.Visual = myStackPanel

            ' Create a rectangle to paint.
            Dim myRectangle As New Rectangle()
            With myRectangle
                .Width = 150
                .Height = 150
                .Stroke = Brushes.Black
                .Margin = New Thickness(5, 0, 5, 0)
            End With

            ' Use myVisualBrush to paint myRectangle.
            myRectangle.Fill = myVisualBrush

The preceding example showed how to create a new Visual for use as a background. You can also use a VisualBrush to display an existing visual; this capability enables you to produce interesting visual effects, such as reflections and magnification. The following example uses a VisualBrush to create a reflection of a Border that contains several elements. The following illustration shows the output that this example produces.

A reflected Visual object
A reflected Visual object

Imports System
Imports System.Windows
Imports System.Windows.Data
Imports System.Windows.Controls
Imports System.Windows.Media
Imports System.Windows.Media.Effects
Imports System.Windows.Media.Imaging
Imports System.IO
Imports System.Collections.ObjectModel
Imports System.Windows.Shapes
Namespace SDKSample
	Partial Public Class ReflectionExample
		Inherits Page
		Public Sub New()
			' Create a name scope for the page.
			NameScope.SetNameScope(Me, New NameScope())

			Me.Background = Brushes.Black
			Dim myStackPanel As New StackPanel()
			myStackPanel.Margin = New Thickness(50)

			Dim myReflectedBorder As New Border()
			Me.RegisterName("ReflectedVisual", myReflectedBorder)

			' Create a gradient background for the border.
			Dim firstStop As New GradientStop()
			firstStop.Offset = 0.0
			Dim firstStopColor As New Color()
			firstStopColor.R = 204
			firstStopColor.G = 204
			firstStopColor.B = 255
			firstStopColor.A = 255
			firstStop.Color = firstStopColor
			Dim secondStop As New GradientStop()
			secondStop.Offset = 1.0
			secondStop.Color = Colors.White

			Dim myGradientStopCollection As New GradientStopCollection()

			Dim myLinearGradientBrush As New LinearGradientBrush()
			myLinearGradientBrush.StartPoint = New Point(0, 0.5)
			myLinearGradientBrush.EndPoint = New Point(1, 0.5)
			myLinearGradientBrush.GradientStops = myGradientStopCollection

			myReflectedBorder.Background = myLinearGradientBrush

			' Add contents to the border.
			Dim borderStackPanel As New StackPanel()
			borderStackPanel.Orientation = Orientation.Horizontal
			borderStackPanel.Margin = New Thickness(10)

			Dim myTextBlock As New TextBlock()
			myTextBlock.TextWrapping = TextWrapping.Wrap
			myTextBlock.Width = 200
			myTextBlock.Text = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit." & " Suspendisse vel ante. Donec luctus tortor sit amet est." & " Nullam pulvinar odio et wisi." & " Pellentesque quis magna. Sed pellentesque." & " Nulla euismod." & "Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas."


			Dim ellipseStackPanel As New StackPanel()

			Dim ellipse1 As New Ellipse()
			ellipse1.Margin = New Thickness(10)
			ellipse1.Height = 50
			ellipse1.Width = 50
			ellipse1.Fill = Brushes.Black
			Dim ellipse2 As New Ellipse()
			ellipse2.Margin = New Thickness(10)
			ellipse2.Height = 50
			ellipse2.Width = 50
			ellipse2.Fill = Brushes.Black
			Dim ellipse3 As New Ellipse()
			ellipse3.Margin = New Thickness(10)
			ellipse3.Height = 50
			ellipse3.Width = 50
			ellipse3.Fill = Brushes.Black

			myReflectedBorder.Child = borderStackPanel

			' Create divider rectangle
			Dim dividerRectangle As New Rectangle()
			dividerRectangle.Height = 1
			dividerRectangle.Fill = Brushes.Gray
			dividerRectangle.HorizontalAlignment = HorizontalAlignment.Stretch

			' Create the object to contain the reflection.
			Dim reflectionRectangle As New Rectangle()

			' Bind the height of the rectangle to the border height.
			Dim heightBinding As New Binding()
			heightBinding.ElementName = "ReflectedVisual"
			heightBinding.Path = New PropertyPath(Rectangle.HeightProperty)
			BindingOperations.SetBinding(reflectionRectangle, Rectangle.HeightProperty, heightBinding)

			' Bind the width of the rectangle to the border width.
			Dim widthBinding As New Binding()
			widthBinding.ElementName = "ReflectedVisual"
			widthBinding.Path = New PropertyPath(Rectangle.WidthProperty)
			BindingOperations.SetBinding(reflectionRectangle, Rectangle.WidthProperty, widthBinding)

			' Creates the reflection.
			Dim myVisualBrush As New VisualBrush()
			myVisualBrush.Opacity = 0.75
			myVisualBrush.Stretch = Stretch.None
			Dim reflectionBinding As New Binding()
			reflectionBinding.ElementName = "ReflectedVisual"
			BindingOperations.SetBinding(myVisualBrush, VisualBrush.VisualProperty, reflectionBinding)

			Dim myScaleTransform As New ScaleTransform()
			myScaleTransform.ScaleX = 1
			myScaleTransform.ScaleY = -1
			Dim myTranslateTransform As New TranslateTransform()
			myTranslateTransform.Y = 1

			Dim myTransformGroup As New TransformGroup()

			myVisualBrush.RelativeTransform = myTransformGroup

			reflectionRectangle.Fill = myVisualBrush

			' Create a gradient background for the border.
			Dim firstStop2 As New GradientStop()
			firstStop2.Offset = 0.0
			Dim c1 As New Color()
			c1.R = 0
			c1.G = 0
			c1.B = 0
			c1.A = 255
			firstStop2.Color = c1
			Dim secondStop2 As New GradientStop()
			secondStop2.Offset = 0.5
			Dim c2 As New Color()
			c2.R = 0
			c2.G = 0
			c2.B = 0
			c2.A = 51
			firstStop2.Color = c2
			Dim thirdStop As New GradientStop()
			thirdStop.Offset = 0.75
			Dim c3 As New Color()
			c3.R = 0
			c3.G = 0
			c3.B = 0
			c3.A = 0
			thirdStop.Color = c3

			Dim myGradientStopCollection2 As New GradientStopCollection()

			Dim myLinearGradientBrush2 As New LinearGradientBrush()
			myLinearGradientBrush2.StartPoint = New Point(0.5, 0)
			myLinearGradientBrush2.EndPoint = New Point(0.5, 1)
			myLinearGradientBrush2.GradientStops = myGradientStopCollection2

			reflectionRectangle.OpacityMask = myLinearGradientBrush2

			Dim myBlurBitmapEffect As New BlurBitmapEffect()
			myBlurBitmapEffect.Radius = 1.5

			reflectionRectangle.BitmapEffect = myBlurBitmapEffect

			Me.Content = myStackPanel

		End Sub
    End Class
End Namespace

  <StackPanel Margin="50">

    <!-- The object to reflect. -->
    <Border Name="ReflectedVisual" Width="400">
        <LinearGradientBrush StartPoint="0,0.5" EndPoint="1,0.5">
          <GradientStop Offset="0.0" Color="#CCCCFF" />
          <GradientStop Offset="1.0" Color="White" />
      <StackPanel Orientation="Horizontal" Margin="10">        
        <TextBlock TextWrapping="Wrap" Width="200" Margin="10">
          Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
          Suspendisse vel ante. Donec luctus tortor sit amet est.
          Nullam pulvinar odio et wisi.
          Pellentesque quis magna. Sed pellentesque.
          Nulla euismod.
          Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.
          <Ellipse Margin="10" Height="50" Width="50" Fill="Black" />
          <Ellipse Margin="10" Height="50" Width="50" Fill="Black" />
          <Ellipse Margin="10" Height="50" Width="50" Fill="Black" />

    <Rectangle Height="1" Fill="Gray" HorizontalAlignment="Stretch" />

    <!-- The object to contain the reflection.-->
      Height="{Binding Path=ActualHeight, ElementName=ReflectedVisual}" 
      Width="{Binding Path=ActualWidth, ElementName=ReflectedVisual}">

        <!-- Creates the reflection. -->
          Opacity="0.75" Stretch="None"
          Visual="{Binding ElementName=ReflectedVisual}">

            <!-- Flip the reflection. -->
              <ScaleTransform ScaleX="1" ScaleY="-1" />
              <TranslateTransform  Y="1" />

        <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
          <GradientStop Color="#FF000000" Offset="0.0" />
          <GradientStop Color="#33000000" Offset="0.5" />
          <GradientStop Color="#00000000" Offset="0.75" />

        <BlurBitmapEffect Radius="1.5" />

For additional examples that show how to magnify portions of the screen and how to create reflections, see the VisualBrush Sample.

ImageBrush, DrawingBrush, and VisualBrush are types of TileBrush objects. TileBrush objects provide you with a great deal of control over how an area is painted with an image, drawing, or visual. For example, instead of just painting an area with a single stretched image, you can paint an area with a series of image tiles that create a pattern.

A TileBrush has three primary components: content, tiles, and the output area.

TileBrush components
Components of a TileBrush with a single tile

Components of a tiled TileBrush
Components of a TileBrush with multiple tiles

For more information about the tiling features of TileBrush objects, see the TileBrush Overview.

TileBrush Overview
WPF Brushes Overview
Imaging Overview
Drawing Objects Overview
Opacity Masks Overview
WPF Graphics Rendering Overview
ImageBrush Sample
VisualBrush Sample