使用图像、绘图和 Visual 进行绘制

更新:2007 年 11 月

本主题描述如何借助 ImageBrushDrawingBrushVisualBrush 对象,使用 Image、DrawingVisual 来绘制区域。

本主题包括下列各节。

  • 先决条件
  • 使用 Image 绘制区域
  • 示例:使用位图图像绘制对象
  • 使用 Drawing 绘制区域
  • 示例:使用 Drawing 绘制对象
  • 使用 Visual 绘制区域
  • 示例:使用 Visual 绘制对象
  • 示例:创建反射
  • TileBrush 功能
  • 相关主题

先决条件

若要了解本主题,您应当熟悉 Windows Presentation Foundation (WPF) 提供的不同类型的画笔及其基本功能。有关介绍,请参见 WPF 画笔概述

使用 Image 绘制区域

ImageBrush 使用 ImageSource 绘制一个区域。与 ImageBrush 一起使用的 ImageSource 的最常见类型是 BitmapImage,它描述一个位图图形。使用 Drawing 对象时,您可以使用 DrawingImage 进行绘制,但是使用 DrawingBrush 会更简单。有关 ImageSource 对象的更多信息,请参见图像处理概述

若要使用 ImageBrush 进行绘制,请创建一个 BitmapImage 并用它来加载位图内容。然后,使用 BitmapImage 来设置 ImageBrushImageSource 属性。最后,将 ImageBrush 应用到想要绘制的对象。在可扩展应用程序标记语言 (XAML) 中,还可以将 ImageBrushImageSource 属性仅设置为要加载的图像的路径。 

与所有 Brush 对象一样,ImageBrush 可用于绘制诸如形状、面板、控件和文本之类的对象。下图显示了利用 ImageBrush 可以实现的几种效果。

使用 ImageBrush 绘制的对象

ImageBrush 输出示例

默认情况下,ImageBrush 会将其图像拉伸以完全充满要绘制的区域,如果绘制的区域和该图像的长宽比不同,则可能会扭曲该图像。您可以通过将 Stretch 属性从默认值 Fill 更改为 NoneUniformUniformToFill 来更改此行为。由于 ImageBrushTileBrush 的一种类型,因此您可以准确指定图像画笔如何填充输出区域,甚至创建图案。有关 TileBrush 高级功能的更多信息,请参见 TileBrush 概述

示例:使用位图图像绘制对象

以下示例使用 ImageBrush 绘制 CanvasBackground

<Page
  xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
  x:Class="Microsoft.Samples.BrushExamples.ImageBrushExample"
  WindowTitle="ImageBrush Example"
  Background="White">

  <StackPanel>

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


  </StackPanel>
</Page>
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace Microsoft.Samples.BrushExamples
{

    public class ImageBrushExample : Page
    {

        public ImageBrushExample()
        {

            StackPanel mainPanel = new StackPanel();
            canvasBackgroundExample(mainPanel);
            this.Content = mainPanel;

        }


        private void canvasBackgroundExample(Panel mainPanel)
        {

            BitmapImage theImage = new BitmapImage
                (new Uri("sampleImages\\Waterlilies.jpg", UriKind.Relative));

            ImageBrush myImageBrush = new ImageBrush(theImage);

            Canvas myCanvas = new Canvas();
            myCanvas.Width = 300;
            myCanvas.Height = 200;
            myCanvas.Background = myImageBrush;

            mainPanel.Children.Add(myCanvas);


        }

    }

}

使用 Drawing 绘制区域

可以使用 DrawingBrush 来绘制具有形状、文本、图像和视频的区域。绘图画笔内的形状可能本身就是使用纯色、渐变、图像甚至其他 DrawingBrush 绘制而成的。下图演示了 DrawingBrush 的一些用法。

使用 DrawingBrush 绘制的对象

DrawingBrush 输出示例

DrawingBrush 使用 Drawing 对象绘制区域。Drawing 对象描述一些可见内容,例如形状、位图、视频或一行文本。不同类型的 Drawing 描绘的是不同类型的内容。下面列出了不同类型的 Drawing 对象。

有关 Drawing 对象的更多信息,请参见 Drawing 对象概述

如同 ImageBrushDrawingBrush 也会拉伸其 Drawing 以填充其输出区域。可以通过更改 Stretch 属性的默认设置 Fill 来重写此行为。有关更多信息,请参见 Stretch 属性。

示例:使用 Drawing 绘制对象

下面的示例演示如何使用一个具有三个椭圆的 Drawing 来绘制对象。GeometryDrawing 用于描述这些椭圆。

<Button Content="A Button">
  <Button.Background>
    <DrawingBrush>
      <DrawingBrush.Drawing>
        <GeometryDrawing Brush="LightBlue">
          <GeometryDrawing.Geometry>
            <GeometryGroup>
              <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" />
            </GeometryGroup>
          </GeometryDrawing.Geometry>
          <GeometryDrawing.Pen>
            <Pen Thickness="1" Brush="Gray" />
          </GeometryDrawing.Pen>
        </GeometryDrawing>
      </DrawingBrush.Drawing>
    </DrawingBrush>
  </Button.Background>
</Button>
// Create a DrawingBrush.
DrawingBrush myDrawingBrush = new DrawingBrush();

// Create a drawing.
GeometryDrawing myGeometryDrawing = new GeometryDrawing();
myGeometryDrawing.Brush = Brushes.LightBlue;
myGeometryDrawing.Pen = new Pen(Brushes.Gray, 1);
GeometryGroup ellipses = 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;

Button myButton = new Button();
myButton.Content = "A Button";

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

使用 Visual 绘制区域

VisualBrush 在所有画笔中功能最多、最强大,它使用 Visual 来绘制一个区域。Visual 是一种低级别的图形类型,用作很多有用的图形组件的上级。例如,WindowFrameworkElementControl 类都是 Visual 对象的类型。如果使用 VisualBrush,则可以使用几乎所有的 Windows Presentation Foundation (WPF) 图形对象来绘制区域。

说明:

尽管 VisualBrush 是一种 Freezable 对象,但是当其 Visual 属性设置为非 null 的值时,无法将其冻结(设置为只读)。

指定 VisualBrushVisual 内容有两种方法。

  • 创建一个新 Visual,并使用它来设置 VisualBrushVisual 属性。有关示例,请参见下面的示例:使用 Visual 绘制对象一节。

  • 使用现有 Visual,这会创建目标 Visual 的重复图像。然后可以使用 VisualBrush 来创建一些有趣的效果,例如反射和放大。有关示例,请参见示例:创建反射一节。

如果您为 VisualBrush 定义了一个新的 Visual,并且该 Visual 是一个 UIElement (例如面板或控件),则当 AutoLayoutContent 属性设置为 true 时,布局系统在 UIElement 及其子元素上运行。不过,此根 UIElement 实际上是与系统的其余部分隔离的,样式和外部布局无法充满此边界。因此,应该显式指定该根 UIElement 的大小,这是因为其唯一父级是 VisualBrush,所以自己无法自动调整大小以适合要绘制的区域。有关 Windows Presentation Foundation (WPF) 中布局的更多信息,请参见布局系统

如同 ImageBrushDrawingBrushVisualBrush 也会拉伸其内容以填充其输出区域。可以通过更改 Stretch 属性的默认设置 Fill 来重写此行为。有关更多信息,请参见 Stretch 属性。

示例:使用 Visual 绘制对象

在下面的示例中,将使用几个控件和一个面板来绘制一个矩形。

<Rectangle Width="150" Height="150" Stroke="Black" Margin="5,0,5,0">
  <Rectangle.Fill>
    <VisualBrush>
      <VisualBrush.Visual>
        <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>
        </StackPanel>
      </VisualBrush.Visual>
    </VisualBrush>
  </Rectangle.Fill>
</Rectangle>
VisualBrush myVisualBrush = new VisualBrush();

// Create the visual brush's contents.
StackPanel myStackPanel = new StackPanel();
myStackPanel.Background = Brushes.White;

Rectangle redRectangle = new Rectangle();
redRectangle.Width = 25;
redRectangle.Height =25; 
redRectangle.Fill = Brushes.Red;
redRectangle.Margin = new Thickness(2);
myStackPanel.Children.Add(redRectangle);

TextBlock someText = new TextBlock();
FontSizeConverter myFontSizeConverter = new FontSizeConverter();
someText.FontSize = (double)myFontSizeConverter.ConvertFrom("10pt");
someText.Text = "Hello, World!";
someText.Margin = new Thickness(2);
myStackPanel.Children.Add(someText);

Button aButton = new Button();
aButton.Content = "A Button";
aButton.Margin = new Thickness(2);
myStackPanel.Children.Add(aButton);

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

// Create a rectangle to paint.
Rectangle myRectangle = new Rectangle();
myRectangle.Width = 150;
myRectangle.Height = 150;
myRectangle.Stroke = Brushes.Black;
myRectangle.Margin = new Thickness(5,0,5,0);

// Use myVisualBrush to paint myRectangle.
myRectangle.Fill = myVisualBrush;

示例:创建反射

上面的示例演示如何新建一个 Visual 来用作背景。您还可以使用 VisualBrush 显示现有可视效果;您可以使用此功能生成有趣的视觉效果,例如反射和放大。下面的示例使用 VisualBrush 创建包含若干元素的 Border 的反射。下面的插图演示此示例生成的输出。

反射的 Visual 对象

反射的 Visual 对象

using System;
using System.Windows;
using System.Windows.Data;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Effects;
using System.Windows.Media.Imaging;
using System.IO;
using System.Collections.ObjectModel;
using System.Windows.Shapes;
namespace SDKSample
{
    public partial class ReflectionExample : Page
    {
        public ReflectionExample()
        {
            // Create a name scope for the page.
            NameScope.SetNameScope(this, new NameScope());

            this.Background = Brushes.Black;
            StackPanel myStackPanel = new StackPanel();
            myStackPanel.Margin = new Thickness(50);

            Border myReflectedBorder = new Border();
            this.RegisterName("ReflectedVisual", myReflectedBorder);

            // Create a gradient background for the border.
            GradientStop firstStop = new GradientStop();
            firstStop.Offset = 0.0;
            Color firstStopColor = new Color();
            firstStopColor.R = 204;
            firstStopColor.G = 204;
            firstStopColor.B = 255;
            firstStopColor.A = 255;
            firstStop.Color = firstStopColor;
            GradientStop secondStop = new GradientStop();
            secondStop.Offset = 1.0;
            secondStop.Color = Colors.White;

            GradientStopCollection myGradientStopCollection = new GradientStopCollection();
            myGradientStopCollection.Add(firstStop);
            myGradientStopCollection.Add(secondStop);

            LinearGradientBrush myLinearGradientBrush = 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.
            StackPanel borderStackPanel = new StackPanel();
            borderStackPanel.Orientation = Orientation.Horizontal;
            borderStackPanel.Margin = new Thickness(10);

            TextBlock myTextBlock = 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.";

            borderStackPanel.Children.Add(myTextBlock);

            StackPanel ellipseStackPanel = new StackPanel();

            Ellipse ellipse1 = new Ellipse();
            ellipse1.Margin = new Thickness(10);
            ellipse1.Height = 50;
            ellipse1.Width = 50;
            ellipse1.Fill = Brushes.Black;
            ellipseStackPanel.Children.Add(ellipse1);
            Ellipse ellipse2 = new Ellipse();
            ellipse2.Margin = new Thickness(10);
            ellipse2.Height = 50;
            ellipse2.Width = 50;
            ellipse2.Fill = Brushes.Black;
            ellipseStackPanel.Children.Add(ellipse2);
            Ellipse ellipse3 = new Ellipse();
            ellipse3.Margin = new Thickness(10);
            ellipse3.Height = 50;
            ellipse3.Width = 50;
            ellipse3.Fill = Brushes.Black;
            ellipseStackPanel.Children.Add(ellipse3);
            borderStackPanel.Children.Add(ellipseStackPanel);

            myReflectedBorder.Child = borderStackPanel;

            // Create divider rectangle
            Rectangle dividerRectangle = new Rectangle();
            dividerRectangle.Height = 1;
            dividerRectangle.Fill = Brushes.Gray;
            dividerRectangle.HorizontalAlignment = HorizontalAlignment.Stretch;

            // Create the object to contain the reflection.
            Rectangle reflectionRectangle = new Rectangle();

            // Bind the height of the rectangle to the border height.
            Binding heightBinding = 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.
            Binding widthBinding = new Binding();
            widthBinding.ElementName = "ReflectedVisual";
            widthBinding.Path = new PropertyPath(Rectangle.WidthProperty);
            BindingOperations.SetBinding(reflectionRectangle, Rectangle.WidthProperty, widthBinding);

            // Creates the reflection.
            VisualBrush myVisualBrush = new VisualBrush();
            myVisualBrush.Opacity = 0.75;
            myVisualBrush.Stretch = Stretch.None;
            Binding reflectionBinding = new Binding();
            reflectionBinding.ElementName = "ReflectedVisual";
            BindingOperations.SetBinding(myVisualBrush, VisualBrush.VisualProperty, reflectionBinding);

            ScaleTransform myScaleTransform = new ScaleTransform();
            myScaleTransform.ScaleX = 1;
            myScaleTransform.ScaleY = -1;
            TranslateTransform myTranslateTransform = new TranslateTransform();
            myTranslateTransform.Y = 1;

            TransformGroup myTransformGroup = new TransformGroup();
            myTransformGroup.Children.Add(myScaleTransform);
            myTransformGroup.Children.Add(myTranslateTransform);

            myVisualBrush.RelativeTransform = myTransformGroup;

            reflectionRectangle.Fill = myVisualBrush;

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

            GradientStopCollection myGradientStopCollection2 = new GradientStopCollection();
            myGradientStopCollection2.Add(firstStop2);
            myGradientStopCollection2.Add(secondStop2);
            myGradientStopCollection2.Add(thirdStop);

            LinearGradientBrush myLinearGradientBrush2 = new LinearGradientBrush();
            myLinearGradientBrush2.StartPoint = new Point(0.5, 0);
            myLinearGradientBrush2.EndPoint = new Point(0.5, 1);
            myLinearGradientBrush2.GradientStops = myGradientStopCollection2;

            reflectionRectangle.OpacityMask = myLinearGradientBrush2;

            BlurBitmapEffect myBlurBitmapEffect = new BlurBitmapEffect();
            myBlurBitmapEffect.Radius = 1.5;

            reflectionRectangle.BitmapEffect = myBlurBitmapEffect;

            myStackPanel.Children.Add(myReflectedBorder);
            myStackPanel.Children.Add(dividerRectangle);
            myStackPanel.Children.Add(reflectionRectangle);
            this.Content = myStackPanel;

        }
        /*
    <Rectangle 
      Height="{Binding Path=ActualHeight, ElementName=ReflectedVisual}" 
      Width="{Binding Path=ActualWidth, ElementName=ReflectedVisual}">

      <Rectangle.OpacityMask>
        <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" />
        </LinearGradientBrush>
      </Rectangle.OpacityMask>

      <Rectangle.BitmapEffect>
        <BlurBitmapEffect Radius="1.5" />
      </Rectangle.BitmapEffect>

    </Rectangle>
  </StackPanel>
</Page>

*/

    }
}
<Page  
  xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" 
  xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" 
  Background="Black">


  <StackPanel Margin="50">

    <!-- The object to reflect. -->
    <Border Name="ReflectedVisual" Width="400">
      <Border.Background>
        <LinearGradientBrush StartPoint="0,0.5" EndPoint="1,0.5">
          <GradientStop Offset="0.0" Color="#CCCCFF" />
          <GradientStop Offset="1.0" Color="White" />
        </LinearGradientBrush>
      </Border.Background>
      <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.
        </TextBlock>
        <StackPanel>
          <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" />
        </StackPanel>
      </StackPanel>
    </Border>

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

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

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

            <!-- Flip the reflection. -->
            <TransformGroup>
              <ScaleTransform ScaleX="1" ScaleY="-1" />
              <TranslateTransform  Y="1" />
            </TransformGroup>
          </VisualBrush.RelativeTransform>
        </VisualBrush>
      </Rectangle.Fill>

      <Rectangle.OpacityMask>
        <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" />
        </LinearGradientBrush>
      </Rectangle.OpacityMask>

      <Rectangle.BitmapEffect>
        <BlurBitmapEffect Radius="1.5" />
      </Rectangle.BitmapEffect>

    </Rectangle>
  </StackPanel>
</Page>

有关演示如何放大屏幕的各部分以及如何创建反射的其他示例,请参见 VisualBrush 示例

TileBrush 功能

ImageBrushDrawingBrushVisualBrush 都是 TileBrush 对象的类型。TileBrush 对象为如何使用 Image、Drawing 或 Visual 绘制区域提供了大量的控制功能。例如,在绘制一个区域时,您可以使用一系列的图像图块创建图案,而不是仅使用拉伸的图像。

TileBrush 包括三个主要的组件:内容、图块和输出区域。

具有单个图块的 TileBrush 的各组成部分

TileBrush 组件

具有多个图块的 TileBrush 的各组成部分

平铺 TileBrush 的组成部分

有关 TileBrush 对象的图块平铺功能的更多信息,请参见 TileBrush 概述

请参见

任务

ImageBrush 示例

DrawingBrush 示例

VisualBrush 示例

概念

TileBrush 概述

WPF 画笔概述

图像处理概述

Drawing 对象概述

不透明遮罩概述

Windows Presentation Foundation 图形呈现概述

参考

ImageBrush

DrawingBrush

VisualBrush

TileBrush