Рисование с помощью объектов Image, Drawing и Visual

Обновлен: Ноябрь 2007

В этом разделе описывается использование объектов ImageBrush, DrawingBrush и VisualBrush для рисования в области с помощью изображения, Drawing или Visual.

В этом разделе содержатся следующие подразделы.

  • Необходимые компоненты
  • Закрашивание области с помощью Image
  • Пример: закрашивание объекта с помощью точечного рисунка
  • Закрашивание области с помощью Drawing
  • Пример: закрашивание объекта с помощью Drawing
  • Закрашивание области с помощью Visual
  • Пример: закрашивание объекта с помощью Visual
  • Пример: создание отражения
  • Функциональные возможности TileBrush
  • Связанные разделы

Необходимые компоненты

Чтобы разобраться в этом разделе, необходимо ознакомиться с различными типами кистей, предоставляемых Windows Presentation Foundation (WPF), и их основными функциями. Общие сведения см. в разделе Общие сведения о кистях WPF.

Закрашивание области с помощью Image

ImageBrush закрашивает область с помощью ImageSource. Наиболее распространенным типом ImageSource для использования с ImageBrush является BitmapImage, который описывает растровую графику. Можно использовать DrawingImage для рисования с помощью объекта Drawing, но проще воспользоваться DrawingBrush. Дополнительные сведения об объектах ImageSource см. в разделе Общие сведения об обработке изображений.

Для рисования с помощью ImageBrush, создайте BitmapImage и используйте его для загрузки растрового содержимого. Затем используйте BitmapImage, чтобы задать свойство ImageSource для ImageBrush. Наконец, примените ImageBrush к объекту рисования. В Язык XAML (Extensible Application Markup Language) можно просто задать путь к загружаемому изображению в свойстве ImageSource для ImageBrush

Как и все объекты Brush, ImageBrush можно использовать для рисования таких объектов, как фигуры, панели, элементы управления и текст. На следующем рисунке показаны некоторые эффекты, которых можно добиться с помощью ImageBrush.

Объекты, нарисованные с помощью ImageBrush
Примеры вывода ImageBrush

По умолчанию ImageBrush растягивает изображения до полного заполнения закрашиваемой области и может искажать изображение, если закрашиваемая область имеет отличные от изображения пропорции. Такое поведение можно изменить путем изменения в свойстве Stretch значения по умолчанию Fill на None, Uniform или UniformToFill. Поскольку ImageBrush является типом TileBrush, можно точно указать, как кисть растровых изображений должна заполнять выходную область, и даже создавать шаблоны. Сведения о дополнительных возможностях TileBrush см. в разделе Общие сведения о TileBrush.

Пример: закрашивание объекта с помощью точечного рисунка

В следующем примере используется ImageBrush для закрашивания Background объекта Canvas.

<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 описывает отображаемое содержимое, такое как фигура, точечный рисунок, видео или строка текста. Различные типы графических объектов описывают различные типы содержимого. Ниже приведен список различных типов графических объектов.

  • GeometryDrawing выводит фигуру.

  • ImageDrawing выводит изображение.

  • GlyphRunDrawing выводит текст.

  • VideoDrawing воспроизводит аудио- или видеофайл.

  • DrawingGroup выводит другие объекты Drawing. Используйте группировку изображений для объединения других рисунков в один составной рисунок.

Дополнительные сведения об объектах Drawing см. в разделе Обзор объектов Drawing.

Подобно ImageBrush, DrawingBrush растягивает его Drawing до заполнения выходной области. Можно переопределить это поведение путем изменения свойства Stretch из значения по умолчанию Fill. Дополнительные сведения см. в описании свойства Stretch.

Пример: закрашивание объекта с помощью 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 является графическим типом нижнего уровня, который служит в качестве предка многих полезных графических компонентов. Например, классы Window, FrameworkElement и Control представляют все типы объектов Visual. Используя VisualBrush, можно закрашивать области практически любыми графическими объектами Windows Presentation Foundation (WPF).

ms749021.alert_note(ru-ru,VS.90).gifПримечание.

Хотя VisualBrush является типом объекта Freezable, он не может быть заморожен (сделан доступным только для чтения), когда для его свойства Visual задано значение, отличное от null.

Существует два способа указать содержимое Visual для VisualBrush.

  • Создайте новый Visual и используйте его, чтобы задать свойство Visual для VisualBrush. Пример см. ниже в разделе Пример: закрашивание объекта с помощью Visual.

  • Используйте существующий Visual, который создает дубликат изображения целевого Visual. Затем можно воспользоваться VisualBrush для создания интересных эффектов, таких как отражение и увеличение. Пример см. в разделе Пример: создание отражения.

В случае определения нового Visual для VisualBrush, если этот Visual представляет собой UIElement (такой как панель или элемент управления), система макета выполняется для UIElement и его дочерних элементов при заданном для свойства AutoLayoutContent значении true. Однако корневой UIElement по существу изолирован от остальной системы: стили и внешний макет не могут переходить эту границу. В связи с этим следует явно указать размер корневого UIElement, поскольку его единственным родительским объектом является VisualBrush, из-за чего его размер не может быть автоматически подобран по размеру закрашиваемой области. Дополнительные сведения о макете в Windows Presentation Foundation (WPF) см. в разделе Система макета.

Подобно ImageBrush и DrawingBrush, VisualBrush растягивает свое содержимое до заполнения выходной области. Можно переопределить это поведение путем изменения свойства 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 для отображения существующего объекта Visual; это позволяет создавать интересные визуальные эффекты, такие как отражение и увеличение. В следующем примере 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

ImageBrush, DrawingBrush и VisualBrush являются типами объектов TileBrush. Объекты TileBrush предоставляют практически полный контроль над закрашиванием области с помощью объектов Image, Drawing или Visual. Например, вместо простого закрашивания области одним растянутым изображением можно закрасить область с помощью повторений изображения, образующих узор.

A TileBrush имеет три основных компонента: содержимое, базовый фрагмент и область вывода.

Компоненты TileBrush с одним фрагментом
Компоненты TileBrushКомпоненты TileBrush с несколькими фрагментами
Компоненты мозаичного TileBrush

Дополнительные сведения о возможностях мозаичного заполнения области объектами TileBrush см. в разделе Общие сведения о TileBrush.

См. также

Задачи

Пример использования ImageBrush

Пример использования DrawingBrush

Пример использования VisualBrush

Основные понятия

Общие сведения о TileBrush

Общие сведения о кистях WPF

Общие сведения об обработке изображений

Обзор объектов Drawing

Общие сведения о масках непрозрачности

Обзор графической визуализации Windows Presentation Foundation

Ссылки

ImageBrush

DrawingBrush

VisualBrush

TileBrush