Рисование фигур

Узнайте, как рисовать фигуры, такие как многоточие, прямоугольники, многоугольники и пути. Класс Path — это способ визуализации довольно сложного языка рисования на основе векторов в пользовательском интерфейсе XAML. Например, можно нарисовать кривые Bezier.

Два набора классов определяют область пространства в пользовательском интерфейсе XAML: классы фигур и классы Geometry. Основное различие между этими классами заключается в том, что фигура имеет кисть, связанную с ним и может быть отрисовано на экране, а геометрия просто определяет область пространства и не отображается, если она не помогает вносить сведения в другое свойство пользовательского интерфейса. Фигуру можно рассматривать как UIElement с его границой, определенной геометрией. В этом разделе рассматриваются главным образом классы shape .

Классы фигуры: Line, Ellipse, Rectangle, Polygon, Polyline и Path. Путь интересен, так как он может определять произвольную геометрию, и класс Geometry участвует здесь, так как это один из способов определения частей пути.

UWP и WinUI 2

Важно!

Сведения и примеры в этой статье оптимизированы для приложений, использующих пакет SDK для приложений Windows и WinUI 3, но обычно применимы к приложениям UWP, использующим WinUI 2. См. справочник по API UWP для конкретных сведений и примеров платформы.

В этом разделе содержатся сведения, необходимые для использования элемента управления в приложении UWP или WinUI 2.

API для этих фигур существуют в пространстве имен Windows.UI.Xaml.Shapes .

Заливка и штрих для фигур

Для отрисовки фигуры на холсте приложения необходимо связать кисть с ним. Задайте нужное свойство Fill фигурыв качестве кисти. Дополнительные сведения о кисти см. в разделе "Использование кистей".

Фигура также может иметь штрих, который представляет собой линию, которая рисуется вокруг периметра фигуры. Для росчерка также требуется кисть, которая определяет его внешний вид и должна иметь ненулевое значение для StrokeThickness. StrokeThickness — это свойство, определяющее толщину периметра вокруг края фигуры. Если значение кисти для штриха не указано или если задано значение StrokeThickness равным 0, то граница вокруг фигуры не рисуется.

Эллипс

Эллипс — это фигура с изогнутым периметром. Чтобы создать базовый эллипс, укажите ширину, высоту и кисть для заливки.

В следующем примере создается эллипс с шириной 200 и высотой 200, а в качестве заливки используется SteelBlue цветной SolidColorBrush.

<Ellipse Fill="SteelBlue" Height="200" Width="200" />
var ellipse1 = new Ellipse();
ellipse1.Fill = new SolidColorBrush(Colors.SteelBlue);
ellipse1.Width = 200;
ellipse1.Height = 200;

// When you create a XAML element in code, you have to add
// it to the XAML visual tree. This example assumes you have
// a panel named 'layoutRoot' in your XAML file, like this:
// <Grid x:Name="layoutRoot>
layoutRoot.Children.Add(ellipse1);

Вот отрисованный Эллипс.

A rendered Ellipse.

В этом случае Эллипс является тем, что большинство людей считают кругом, но вот как вы объявляете фигуру круга в XAML: используйте эллипс с равной шириной и высотой.

Если эллипс находится в макете пользовательского интерфейса, его размер считается таким же, как прямоугольник с этой шириной и высотой; область за пределами периметра не имеет отрисовки, но по-прежнему является частью его размера слота макета.

Набор из 6 элементов Ellipse является частью шаблона элемента управления ProgressRing, а 2 концентрические элементы Ellipse являются частью RadioButton.

Rectangle

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

Вы можете округлить угла прямоугольника. Чтобы создать округленные угла, укажите значение для свойств RadiusX и RadiusY. Эти свойства указывают ось x и y многоточия, определяющие кривую углов. Максимально допустимое значение RadiusX ширина, разделенная на две, а максимально допустимое значение RadiusY высота, разделенная на две.

В следующем примере создается прямоугольник с шириной 200 и высотой 100. Он использует синее значение SolidColorBrush для заливки и черное значение SolidColorBrush для его росчерка. Мы задали 3 значения StrokeThickness . Для свойства RadiusX задано значение 50, а свойство RadiusY — 10, что даетпрямоугольникам округленные угла.

<Rectangle Fill="Blue"
           Width="200"
           Height="100"
           Stroke="Black"
           StrokeThickness="3"
           RadiusX="50"
           RadiusY="10" />
var rectangle1 = new Rectangle();
rectangle1.Fill = new SolidColorBrush(Colors.Blue);
rectangle1.Width = 200;
rectangle1.Height = 100;
rectangle1.Stroke = new SolidColorBrush(Colors.Black);
rectangle1.StrokeThickness = 3;
rectangle1.RadiusX = 50;
rectangle1.RadiusY = 10;

// When you create a XAML element in code, you have to add
// it to the XAML visual tree. This example assumes you have
// a panel named 'layoutRoot' in your XAML file, like this:
// <Grid x:Name="layoutRoot>
layoutRoot.Children.Add(rectangle1);

Вот отрисованный прямоугольник.

A rendered Rectangle.

Существуют некоторые сценарии для определений пользовательского интерфейса, где вместо использования прямоугольника может быть более подходящим. Если вы намерены создать прямоугольную фигуру вокруг другого содержимого, лучше использовать границу , так как она может иметь дочернее содержимое и автоматически будет размер вокруг этого содержимого, а не использовать фиксированные размеры для высоты и ширины, как прямоугольник . Граница также имеет возможность скругления углов, если задано свойство CornerRadius.

С другой стороны, прямоугольник, вероятно, лучше подходит для композиции элементов управления. Фигура прямоугольника рассматривается во многих шаблонах элементов управления, так как она используется в качестве части "FocusVisual" для фокусируемых элементов управления. Всякий раз, когда элемент управления находится в визуальном состоянии "Фокус", этот прямоугольник становится видимым, в других состояниях он скрыт.

Многоугольник

Многоугольник — это фигура с границей, определенной произвольным числом точек. Граница создается путем подключения строки из одной точки к следующей, с последней точкой, подключенной к первой точке. Свойство Points определяет коллекцию точек, составляющих границу. В XAML вы определяете точки с разделенным запятыми списком. В коде позади используется PointCollection для определения точек и добавления каждой отдельной точки в качестве значения point в коллекцию.

Вам не нужно явно объявлять точки, такие как начальная точка и конечная точка, указаны как одно и то же значение point. Логика отрисовки для Многоугольника предполагает, что вы определяете закрытую фигуру и подключаете конечную точку к начальной точке неявно.

В следующем примере создается многоугольник с 4 точками, равными (10,200), (60,140)и (130,140)(180,200). Он использует значение LightBlue SolidColorBrush для его заливки и не имеет значения для Штриха, поэтому он не имеет контура периметра.

<Polygon Fill="LightBlue"
         Points="10,200,60,140,130,140,180,200" />
var polygon1 = new Polygon();
polygon1.Fill = new SolidColorBrush(Colors.LightBlue);

var points = new PointCollection();
points.Add(new Windows.Foundation.Point(10, 200));
points.Add(new Windows.Foundation.Point(60, 140));
points.Add(new Windows.Foundation.Point(130, 140));
points.Add(new Windows.Foundation.Point(180, 200));
polygon1.Points = points;

// When you create a XAML element in code, you have to add
// it to the XAML visual tree. This example assumes you have
// a panel named 'layoutRoot' in your XAML file, like this:
// <Grid x:Name="layoutRoot>
layoutRoot.Children.Add(polygon1);

Вот отрисованный многоугольник.

A rendered Polygon.

Совет

Значение точки часто используется в качестве типа в XAML для сценариев, отличных от объявления вершин фигур. Например, точка является частью данных события для сенсорных событий, поэтому вы можете точно знать, где в пространстве координат произошло действие касания. Дополнительные сведения о точке и его использовании в XAML или коде см. в справочном разделе API для Point.

График

Линия — это просто линия, рисуемая между двумя точками в пространстве координат. Строка игнорирует любое значение, предоставленное для заливки, так как оно не имеет внутреннего пространства. Для строки обязательно укажите значения свойств Stroke и StrokeThickness, так как в противном случае строка не будет отображаться.

Значения точек не используются для указания фигуры строки, вместо этого используются дискретные двойные значения для X1, Y1, X2 и Y2. Это обеспечивает минимальную разметку для горизонтальных или вертикальных линий. Например, определяет горизонтальную линию длиной <Line Stroke="Red" X2="400"/> 400 пикселей. Другие свойства X,Y по умолчанию имеют значение 0, поэтому в терминах точек, отрисовывается линия от(0,0).(400,0) Затем вы можете использовать TranslateTransform для перемещения всей строки, если вы хотите, чтобы она начала в точке, отличной от (0,0).

<Line Stroke="Red" X2="400"/>
var line1 = new Line();
line1.Stroke = new SolidColorBrush(Colors.Red);
line1.X2 = 400;

// When you create a XAML element in code, you have to add
// it to the XAML visual tree. This example assumes you have
// a panel named 'layoutRoot' in your XAML file, like this:
// <Grid x:Name="layoutRoot>
layoutRoot.Children.Add(line1);

Polyline

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

Примечание.

Вы можете явно иметь идентичную начальную точку и конечную точку в наборе точек для Polyline, но в этом случае вы, вероятно, могли бы использовать Многоугольник вместо этого.

Если указать заливку полилайна, заливка красит внутреннее пространство фигуры, даже если начальная точка и конечная точка точек, заданных для Polyline, не пересекаются. Если не указать заливку, то Полилайн похож на то, что было бы отрисовывается, если бы вы указали несколько отдельных элементов Line, где точки начала и конечные точки последовательных строк пересекаются.

Как и в случае с Многоугольником, свойство Point определяет коллекцию точек, составляющих границу. В XAML вы определяете точки с разделенным запятыми списком. В коде программной части вы используете PointCollection для определения точек и добавляете каждую отдельную точку в качестве структуры point в коллекцию.

В этом примере создается Polyline с четырьмя точками, равными (10,200), (60,140)(130,140)и (180,200). Штрих определяется, но не заливка.

<Polyline Stroke="Black"
          StrokeThickness="4"
          Points="10,200,60,140,130,140,180,200" />
var polyline1 = new Polyline();
polyline1.Stroke = new SolidColorBrush(Colors.Black);
polyline1.StrokeThickness = 4;

var points = new PointCollection();
points.Add(new Windows.Foundation.Point(10, 200));
points.Add(new Windows.Foundation.Point(60, 140));
points.Add(new Windows.Foundation.Point(130, 140));
points.Add(new Windows.Foundation.Point(180, 200));
polyline1.Points = points;

// When you create a XAML element in code, you have to add
// it to the XAML visual tree. This example assumes you have
// a panel named 'layoutRoot' in your XAML file, like this:
// <Grid x:Name="layoutRoot>
layoutRoot.Children.Add(polyline1);

Вот отрисованная Полилайн. Обратите внимание, что первые и последние точки не связаны контуром росчерка, так как они находятся в многоугольнике.

A rendered Polyline.

Путь

Путь является наиболее универсальной фигурой, так как ее можно использовать для определения произвольной геометрии. Но с этой универсальностью приходит сложность. Теперь рассмотрим, как создать базовый путь в XAML.

Вы определяете геометрию пути со свойством Data . Существует два способа настройки данных:

  • Строковое значение для данных в XAML можно задать. В этой форме значение Path.Data использует формат сериализации для графики. Обычно это значение не редактируется в строковой форме после его создания. Вместо этого вы используете инструменты проектирования, позволяющие работать в конструкторе или рисовании метафоры на поверхности. Затем вы сохраняете или экспортируете выходные данные, а это дает фрагмент строки XAML или xaml со сведениями Path.Data .
  • Свойство Data можно задать для одного объекта Geometry. Это можно сделать в коде или в XAML. Эта одна геометрия обычно является geometryGroup, которая выступает в качестве контейнера, который может составить несколько определений геометрии в один объект для целей объектной модели. Наиболее распространенной причиной этого является то, что вы хотите использовать одну или несколько кривых и сложных фигур, которые можно определить как значения сегментов для PathFigure, например BezierSegment.

В этом примере показано путь, который может привести к использованию Blend для Visual Studio для создания только нескольких векторных фигур, а затем сохранения результата в XAML. Общий путь состоит из сегмента кривой Bezier и сегмента линии. Этот пример в основном предназначен для предоставления некоторых примеров того, какие элементы существуют в формате сериализации Path.Data и какие цифры представляют.

Эти данные начинаются с команды перемещения, указанной "M", которая устанавливает абсолютную начальную точку для пути.

Первый сегмент — это кубическая кривая Bezier, начинающаяся с (100,200) и заканчивается на (400,175), которая рисуется с помощью двух контрольных точек (100,25) и (400,350). Этот сегмент указывается командой "C" в строке атрибута данных .

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

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

Вот отрисованный путь.

Screenshot of a simple rendered path.

В следующем примере показано использование другого метода, который мы обсуждали: GeometryGroup с pathGeometry. В этом примере используются некоторые из типов геометрии, которые можно использовать в рамках PathGeometry: PathFigure и различных элементов, которые могут быть сегментом в PathFigure.Segments.

<Path Stroke="Black" StrokeThickness="1" Fill="#CCCCFF">
    <Path.Data>
        <GeometryGroup>
            <RectangleGeometry Rect="50,5 100,10" />
            <RectangleGeometry Rect="5,5 95,180" />
            <EllipseGeometry Center="100, 100" RadiusX="20" RadiusY="30"/>
            <RectangleGeometry Rect="50,175 100,10" />
            <PathGeometry>
                <PathGeometry.Figures>
                    <PathFigureCollection>
                        <PathFigure IsClosed="true" StartPoint="50,50">
                            <PathFigure.Segments>
                                <PathSegmentCollection>
                                    <BezierSegment Point1="75,300" Point2="125,100" Point3="150,50"/>
                                    <BezierSegment Point1="125,300" Point2="75,100"  Point3="50,50"/>
                                </PathSegmentCollection>
                            </PathFigure.Segments>
                        </PathFigure>
                    </PathFigureCollection>
                </PathGeometry.Figures>
            </PathGeometry>
        </GeometryGroup>
    </Path.Data>
</Path>
var path1 = new Microsoft.UI.Xaml.Shapes.Path();
path1.Fill = new SolidColorBrush(Windows.UI.Color.FromArgb(255, 204, 204, 255));
path1.Stroke = new SolidColorBrush(Colors.Black);
path1.StrokeThickness = 1;

var geometryGroup1 = new GeometryGroup();
var rectangleGeometry1 = new RectangleGeometry();
rectangleGeometry1.Rect = new Rect(50, 5, 100, 10);
var rectangleGeometry2 = new RectangleGeometry();
rectangleGeometry2.Rect = new Rect(5, 5, 95, 180);
geometryGroup1.Children.Add(rectangleGeometry1);
geometryGroup1.Children.Add(rectangleGeometry2);

var ellipseGeometry1 = new EllipseGeometry();
ellipseGeometry1.Center = new Point(100, 100);
ellipseGeometry1.RadiusX = 20;
ellipseGeometry1.RadiusY = 30;
geometryGroup1.Children.Add(ellipseGeometry1);

var pathGeometry1 = new PathGeometry();
var pathFigureCollection1 = new PathFigureCollection();
var pathFigure1 = new PathFigure();
pathFigure1.IsClosed = true;
pathFigure1.StartPoint = new Windows.Foundation.Point(50, 50);
pathFigureCollection1.Add(pathFigure1);
pathGeometry1.Figures = pathFigureCollection1;

var pathSegmentCollection1 = new PathSegmentCollection();
var pathSegment1 = new BezierSegment();
pathSegment1.Point1 = new Point(75, 300);
pathSegment1.Point2 = new Point(125, 100);
pathSegment1.Point3 = new Point(150, 50);
pathSegmentCollection1.Add(pathSegment1);

var pathSegment2 = new BezierSegment();
pathSegment2.Point1 = new Point(125, 300);
pathSegment2.Point2 = new Point(75, 100);
pathSegment2.Point3 = new Point(50, 50);
pathSegmentCollection1.Add(pathSegment2);
pathFigure1.Segments = pathSegmentCollection1;

geometryGroup1.Children.Add(pathGeometry1);
path1.Data = geometryGroup1;

// When you create a XAML element in code, you have to add
// it to the XAML visual tree. This example assumes you have
// a panel named 'layoutRoot' in your XAML file, like this:
// <Grid x:Name="layoutRoot">
layoutRoot.Children.Add(path1);

Вот отрисованный путь.

Screenshot of a complex rendered path.

Использование PathGeometry может быть более удобочитаемым, чем заполнение строки Path.Data. С другой стороны, Path.Data использует синтаксис, совместимый с определениями пути изображения с масштабируемыми векторными векторами (SVG), поэтому это может быть полезно для переноса графики из SVG или выходных данных из инструмента, например Blend.