Обзор фигур и базовых средств рисования в приложении WPF

В этой теме дается обзор рисования с помощью объектов Shape. Shape — это тип элемента UIElement, позволяющего рисовать фигуры на экране. Так как это элементы пользовательского интерфейса, объекты Shape можно использовать внутри элементов Panel и большинства элементов управления.

WPF предлагает несколько уровней доступа к службам для работы с графикой и службам рендеринга. На верхнем уровне объекты Shape просты в использовании и предоставляют доступ ко многим удобным функциям, таким как макет и участие в системе событий WPF.

Объекты фигур

WPF предоставляет ряд готовых к использованию объектов Shape. Все объекты фигуры наследуют от класса Shape. Доступные объекты фигур: Ellipse, Line, Path, Polygon, Polyline и Rectangle. Объекты Shape обладают следующими общими свойствами.

  • Stroke описывает способ закрашивания внутренней области фигуры.

  • StrokeThickness описывается толщину линий контура фигуры.

  • Fill описывает способ рисования внутренней области фигуры.

  • Свойства данных, определяющие координаты и вершины, измеряются в аппаратно-независимых пикселях.

Так как объекты фигур наследуются от элемента UIElement, их можно использовать внутри панелей и большинства элементов управления. Панель Canvas — отличный вариант для создания сложных рисунков, так как при ее использовании можно указать абсолютное положение дочерних объектов.

Класс Line позволяет нарисовать линию между двумя точками. В следующем примере показано несколько способов указания координат линии и свойств штриха.

<Canvas Height="300" Width="300">

  <!-- Draws a diagonal line from (10,10) to (50,50). -->
  <Line
    X1="10" Y1="10"
    X2="50" Y2="50"
    Stroke="Black"
    StrokeThickness="4" />

  <!-- Draws a diagonal line from (10,10) to (50,50)
       and moves it 100 pixels to the right. -->
  <Line
    X1="10" Y1="10"
    X2="50" Y2="50"
    StrokeThickness="4"
    Canvas.Left="100">
    <Line.Stroke>
      <RadialGradientBrush GradientOrigin="0.5,0.5" Center="0.5,0.5" RadiusX="0.5" RadiusY="0.5">
        <RadialGradientBrush.GradientStops>
          <GradientStop Color="Red" Offset="0" />
          <GradientStop Color="Blue" Offset="0.25" />
        </RadialGradientBrush.GradientStops>
      </RadialGradientBrush>
    </Line.Stroke>
  </Line>

  <!-- Draws a horizontal line from (10,60) to (150,60). -->
  <Line
     X1="10" Y1="60"
     X2="150" Y2="60"
     Stroke="Black"
     StrokeThickness="4"/>

</Canvas>

// Add a Line Element
myLine = gcnew Line();
myLine->Stroke = Brushes::LightSteelBlue;
myLine->X1 = 1;
myLine->X2 = 50;
myLine->Y1 = 1;
myLine->Y2 = 50;
myLine->HorizontalAlignment = HorizontalAlignment::Left;
myLine->VerticalAlignment = VerticalAlignment::Center;
myLine->StrokeThickness = 2;
myGrid->Children->Add(myLine);

// Add a Line Element
myLine = new Line();
myLine.Stroke = System.Windows.Media.Brushes.LightSteelBlue;
myLine.X1 = 1;
myLine.X2 = 50;
myLine.Y1 = 1;
myLine.Y2 = 50;
myLine.HorizontalAlignment = HorizontalAlignment.Left;
myLine.VerticalAlignment = VerticalAlignment.Center;
myLine.StrokeThickness = 2;
myGrid.Children.Add(myLine);

' Add a Line Element
Dim myLine As New Line()
myLine.Stroke = Brushes.LightSteelBlue
myLine.X1 = 1
myLine.X2 = 50
myLine.Y1 = 1
myLine.Y2 = 50
myLine.HorizontalAlignment = HorizontalAlignment.Left
myLine.VerticalAlignment = VerticalAlignment.Center
myLine.StrokeThickness = 2
myGrid.Children.Add(myLine)

На следующем рисунке показана преобразованная для просмотра линия Line.

Line illustration

Хотя класс Line предоставляет свойство Fill, его настройка не имеет никакого эффекта, так как у линии Line нет площади.

Еще одна распространенная фигура — Ellipse. Создайте Ellipse, определив свойства фигуры Width и Height. Чтобы нарисовать окружность, укажите фигуру Ellipse, у которой значения свойств Width и Height равны.

<Ellipse
Fill="Yellow"
Height="100"
Width="200"
StrokeThickness="2"
Stroke="Black"/>

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;

namespace SDKSample
{
    public partial class SetBackgroundColorOfShapeExample : Page
    {
        public SetBackgroundColorOfShapeExample()
        {
            // Create a StackPanel to contain the shape.
            StackPanel myStackPanel = new StackPanel();

            // Create a red Ellipse.
            Ellipse myEllipse = new Ellipse();

            // Create a SolidColorBrush with a red color to fill the
            // Ellipse with.
            SolidColorBrush mySolidColorBrush = new SolidColorBrush();

            // Describes the brush's color using RGB values.
            // Each value has a range of 0-255.
            mySolidColorBrush.Color = Color.FromArgb(255, 255, 255, 0);
            myEllipse.Fill = mySolidColorBrush;
            myEllipse.StrokeThickness = 2;
            myEllipse.Stroke = Brushes.Black;

            // Set the width and height of the Ellipse.
            myEllipse.Width = 200;
            myEllipse.Height = 100;

            // Add the Ellipse to the StackPanel.
            myStackPanel.Children.Add(myEllipse);

            this.Content = myStackPanel;
        }
    }
}

Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Media
Imports System.Windows.Shapes

Namespace SDKSample
    Partial Public Class SetBackgroundColorOfShapeExample
        Inherits Page
        Public Sub New()
            ' Create a StackPanel to contain the shape.
            Dim myStackPanel As New StackPanel()

            ' Create a red Ellipse.
            Dim myEllipse As New Ellipse()

            ' Create a SolidColorBrush with a red color to fill the 
            ' Ellipse with.
            Dim mySolidColorBrush As New SolidColorBrush()

            ' Describes the brush's color using RGB values. 
            ' Each value has a range of 0-255.
            mySolidColorBrush.Color = Color.FromArgb(255, 255, 255, 0)
            myEllipse.Fill = mySolidColorBrush
            myEllipse.StrokeThickness = 2
            myEllipse.Stroke = Brushes.Black

            ' Set the width and height of the Ellipse.
            myEllipse.Width = 200
            myEllipse.Height = 100

            ' Add the Ellipse to the StackPanel.
            myStackPanel.Children.Add(myEllipse)

            Me.Content = myStackPanel
        End Sub

    End Class
End Namespace

На следующем рисунке показан пример преобразованной для просмотра фигуры Ellipse.

Ellipse illustration

Использование путей и геометрических фигур

Класс Path позволяет рисовать кривые и сложные фигуры. Такие кривые и формы описываются с помощью объектов Geometry. Чтобы использовать класс Path, следует создать объект Geometry и с его помощью задать свойства Data объекта Path.

Есть множество объектов Geometry на выбор. Классы LineGeometry, RectangleGeometry и EllipseGeometry описывают относительно простые фигуры. Чтобы создавать более сложные формы или кривые, используйте PathGeometry.

Классы PathGeometry и PathSegment

Объекты PathGeometry состоят из одного или нескольких объектов PathFigure; каждый объект PathFigure представляет другую фигуру. Каждый объект PathFigure сам по себе состоит из одного или нескольких объектов PathSegment, каждый из них представляет собой связанную часть фигуры. К типам сегментов относятся следующие: LineSegment, BezierSegment и ArcSegment.

В следующем примере с помощью объекта Path создается квадратичная кривая Безье.

<Path Stroke="Black" StrokeThickness="1">
  <Path.Data>
    <PathGeometry>
      <PathGeometry.Figures>
        <PathFigureCollection>
          <PathFigure StartPoint="10,100">
            <PathFigure.Segments>
              <PathSegmentCollection>
                <QuadraticBezierSegment Point1="200,200" Point2="300,100" />
              </PathSegmentCollection>
            </PathFigure.Segments>
          </PathFigure>
        </PathFigureCollection>
      </PathGeometry.Figures>
    </PathGeometry>
  </Path.Data>
</Path>

На следующем рисунке показана преобразованная для просмотра фигура.

Path illustration

Дополнительные сведения о и других классах Geometry см. в статье PathGeometryОбщие сведения о классе Geometry.

Сокращенный синтаксис XAML

В языке XAML для описания Path также можно использовать сокращенный синтаксис разметки. В следующем примере сокращенный синтаксис используется для рисования сложной фигуры.

      <Path Stroke="DarkGoldenRod" StrokeThickness="3"
Data="M 100,200 C 100,25 400,350 400,175 H 280" />  

На следующем рисунке показана преобразованная для просмотра фигура Path.

A second Path illustration.

Строка атрибута Data начинается с команды moveto (обозначена буквой M), которая устанавливает начальную точку пути в системе координат Canvas. Параметры данных Path вводятся с учетом регистра. Заглавная буква M указывает абсолютное положение новой текущей точки. Строчная буква m указывала бы относительные координаты. Первый сегмент представляет собой кубическую кривую Безье, которая начинается в точке (100, 200) и заканчивается в точке (400, 175). Эта кривая нарисована с помощью двух контрольных точек (100, 25) и (400, 350). Этот сегмент отмечен командой C в строке атрибута Data. Опять же, заглавная буква C указывает абсолютный путь; строчная буква c указывает относительный путь.

Второй сегмент начинается с команды lineto H, которая рисует горизонтальную линию от предыдущей точки пути (400, 175) до новой точки (280, 175). Так как эта команда lineto рисует горизонтальную линию, указанное значение представляет собой координату x.

Полный синтаксис пути см. по ссылке Data и в статье Создание фигуры с помощью PathGeometry.

Заполнение фигур

Объекты Brush используются для рисования Stroke и Fill фигуры. В следующем примере указаны штрих и заливка для объекта Ellipse. Обратите внимание, что значения свойств кисти могут задаваться только в формате ключевого слова или шестнадцатеричного значения цвета. Дополнительную информацию о доступных ключевых словах цвета см. свойства класса Colors в пространстве имен System.Windows.Media.

<Canvas Background="LightGray">
   <Ellipse  
      Canvas.Top="50"  
      Canvas.Left="50"  
      Fill="#FFFFFF00"  
      Height="75"  
      Width="75"  
      StrokeThickness="5"  
      Stroke="#FF0000FF"/>  
</Canvas>  

На следующем рисунке показана преобразованная для просмотра линия Ellipse.

An ellipse

Также можно использовать синтаксис элемента свойств, чтобы явно создать объект SolidColorBrush и заполнить фигуру сплошным цветом.

<!-- This polygon shape uses pre-defined color values for its Stroke and  
     Fill properties.   
     The SolidColorBrush's Opacity property affects the fill color in   
     this case by making it slightly transparent (opacity of 0.4) so   
     that it blends with any underlying color. -->  
  
<Polygon  
    Points="300,200 400,125 400,275 300,200"  
    Stroke="Purple"
    StrokeThickness="2">  
    <Polygon.Fill>  
       <SolidColorBrush Color="Blue" Opacity="0.4"/>  
    </Polygon.Fill>  
</Polygon>  

На рисунке ниже показана фигура, преобразованная для просмотра.

SolidColorBrush illustration

Для заполнения фигуры также можно использовать штриховку, градиенты, изображения, шаблоны и многое другое. Дополнительные сведения см. в статье Общие сведения о заполнении сплошным цветом и градиентах.

Растягиваемые фигуры

У всех классов Line, Path, Polygon, Polyline и Rectangle есть свойство Stretch. Это свойство определяет, как содержимое объекта Shape (фигура, которую требуется нарисовать) растягивается, чтобы заполнить пространство макета объекта Shape. Пространство макета объекта Shape — это объем пространства, выделяемый объекту Shape системой макета, либо в результате явного задания свойств Width и Height, либо в результате настройки HorizontalAlignment и VerticalAlignment. Дополнительные сведения о макете в Windows Presentation Foundation см. в статье Общие сведения о макете.

Свойство Stretch принимает одно из следующих значений.

  • None: содержимое объекта Shape не растягивается.

  • Fill: содержимое объекта Shape растягивается, чтобы заполнить пространство макета. Пропорции не сохраняются.

  • Uniform: содержимое объекта Shape растягивается для заполнения пространства макета настолько, насколько это возможно с сохранением исходных пропорций.

  • UniformToFill: содержимое объекта Shape растягивается до полного заполнения пространства макета с сохранением исходных пропорций.

Обратите внимание, что когда растягивается содержимое объекта Shape, макет объекта Shape закрашивается после растягивания.

В следующем примере с помощью объекта Polygon создается очень маленький треугольник с вершинами в точках (0, 0), (0, 1) и (1, 1). У объекта Polygon свойствам Width и Height задано значение 100, а его свойству stretch задается значение Fill. В результате содержимое объекта Polygon (треугольник) растягивается, чтобы заполнить большее пространство.

<Polygon  
  Points="0,0 0,1 1,1"  
  Fill="Blue"  
  Width="100"  
  Height="100"  
  Stretch="Fill"  
  Stroke="Black"  
  StrokeThickness="2" />  
PointCollection myPointCollection = new PointCollection();  
myPointCollection.Add(new Point(0,0));  
myPointCollection.Add(new Point(0,1));  
myPointCollection.Add(new Point(1,1));  
  
Polygon myPolygon = new Polygon();  
myPolygon.Points = myPointCollection;  
myPolygon.Fill = Brushes.Blue;  
myPolygon.Width = 100;  
myPolygon.Height = 100;  
myPolygon.Stretch = Stretch.Fill;  
myPolygon.Stroke = Brushes.Black;  
myPolygon.StrokeThickness = 2;  

Преобразование фигур

Класс Transform предоставляет средства для преобразования фигур в двумерную плоскость. Преобразования различных типов включают поворот (RotateTransform), масштабирование (ScaleTransform), отклонение (SkewTransform) и трансляцию (TranslateTransform).

Распространенным преобразованием фигуры является поворот. Чтобы повернуть фигуру, создайте объект RotateTransform и укажите его угол Angle. Если свойство Angle имеет значение 45, элемент поворачивается на 45 градусов по часовой стрелке; если оно имеет значение 90, элемент поворачивается на 90 градусов по часовой стрелке, и т. д. Задайте свойства CenterX и CenterY, если требуется контролировать точку, относительно которой поворачивается элемент. Эти значения свойств выражаются в системе координат преобразуемого элемента. У CenterX и CenterY значения по умолчанию равны нулю. Наконец, применим RotateTransform к элементу. Если преобразование не должно влиять на макет, задайте свойство RenderTransform фигуры.

В следующем примере метод RotateTransform используется для поворота фигуры на 45 градусов вокруг левого верхнего угла фигуры (0, 0).

<!-- Rotates the Polyline 45 degrees about the point (0,0). -->
<Polyline Points="25,25 0,50 25,75 50,50 25,25 25,0" 
  Stroke="Blue" StrokeThickness="10"
  Canvas.Left="75" Canvas.Top="50">
  <Polyline.RenderTransform>
    <RotateTransform CenterX="0" CenterY="0" Angle="45" />
  </Polyline.RenderTransform>
</Polyline>

В следующем примере другая фигура поворачивается на 45 градусов, но на этот раз — вокруг точки (25, 50).

<!-- Rotates the Polyline 45 degrees about its center. -->
<Polyline 
  Points="25,25 0,50 25,75 50,50 25,25 25,0" 
  Stroke="Blue" StrokeThickness="10"
  Canvas.Left="75" Canvas.Top="50"
  RenderTransformOrigin="0.5,0.5">
  <Polyline.RenderTransform>
    <RotateTransform Angle="45" />
  </Polyline.RenderTransform>
</Polyline>

На следующем рисунке показаны результаты двух преобразований.

45 degree rotations with different center points

В предыдущих примерах к каждому объекту фигуры применяется одно преобразование. Чтобы применить к фигуре (или любому другому элементу пользовательского интерфейса) несколько преобразований, используйте метод TransformGroup.

См. также