Одним из способов построения двухмерной графики в окне - это использование фигур. Фигуры фактически являются обычными элементами как например кнопка или текстовое поле. К фигурам относят такие элементы как Polygon (Многоугольник), Ellipse (представляет собой эллипс), Rectangle (прямоугольник), Line (обычная линия), Polyline - включает несколько линий. Все они наследуются от класса Shape, который определяет ряд общих свойств:
Fill заполняет фон фигуры с помощью кисти - аналогичен свойству Background у прочих элементов
Stroke задает кисть, которая отрисовывает границу фигуры - аналогичен свойству BorderBrush у прочих элементов
StrokeThikness задает толщину границы фигуры - аналогичен свойству BorderThikness у прочих элементов
StrokeStartLineCap и StrokeEndLineCap задают для незамкнутых фигур (Line) контур в начале и в конце линии соответственно
StrokeDashArray задает границу фигуры в виде штриховки, создавая эффект пунктира
StrokeDashOffset задает расстояние до начала штриха
StrokeDashCap задает форму штрихов
Stretch устанавливает способ заполнения внешнего контейнера
GeometryTransform применяет преобразования к объекту Geometry
Ну и как обычные элементы управления они поддерживают традиционные свойства типа Width и Height, а также события, например, Сlick.
Линия (Line) задается с помощью двух координат по оси Х и двух координат по оси У:
<Line Stroke="Red" X1="10" X2="210" Y1="50" Y2="50" />
Элемент Polyline задается с помощью нескольких точек:
<Polyline Points="10,10 50,50 120,10 10,10" Stroke="Red" />
Элемент Polygon (Многоугольник) задается также как и Polyline с помощью нескольких точек, однако при этом первая и последняя точка соединяются между собой, образуя замкнутую линию:
<Polygon Points="10,80 50,50 120,80" Stroke="Red" StrokeThickness="3" StrokeDashArray="1 1 5" />
Элементы Ellipse и Rectangle задаются с помощью свойств Width
и Height
:
<Rectangle Width="60" Height="40" Fill="Beige" /> <Ellipse Width="30" Height="30" Fill="Red" />
Создание фигур на форме осуществляется тем же образом как и создаются и добавляются все остальные элементы:
Ellipse el = new Ellipse(); el.Width = 50; el.Height = 50; el.VerticalAlignment = VerticalAlignment.Top; el.Fill = new SolidColorBrush(Colors.Green); el.Stroke = new SolidColorBrush(Colors.Red); el.StrokeThickness = 3; LayoutRoot.Children.Add(el);
Нарисуем, к примеру, координатную плоскость:
Line vertL =new Line(); vertL.X1 = 10; vertL.Y1 = 150; vertL.X2 = 10; vertL.Y2 = 10; vertL.Stroke = new SolidColorBrush(Colors.Black); LayoutRoot.Children.Add(vertL); Line horL =new Line(); horL.X1 = 10; horL.X2 = 150; horL.Y1 = 150; horL.Y2 = 150; horL.Stroke = new SolidColorBrush(Colors.Black); LayoutRoot.Children.Add(horL); for(byte i = 2;i< 15;i++) { Line a =new Line(); a.X1 = i * 10; a.X2 = i * 10; a.Y1 = 155; a.Y2 = 145; a.Stroke = new SolidColorBrush(Colors.Black); LayoutRoot.Children.Add(a); } for(byte i = 2;i< 15;i++) { Line a =new Line(); a.X1 = 5; a.X2 = 15; a.Y1 = i * 10; a.Y2 = i * 10; a.Stroke = new SolidColorBrush(Colors.Black); LayoutRoot.Children.Add(a); } Polyline vertArr =new Polyline(); vertArr.Points = new PointCollection(); vertArr.Points.Add(new Point(5, 15)); vertArr.Points.Add(new Point(10, 10)); vertArr.Points.Add(new Point(15, 15)); vertArr.Stroke = new SolidColorBrush(Colors.Black); LayoutRoot.Children.Add(vertArr); Polyline horArr =new Polyline(); horArr.Points = new PointCollection(); horArr.Points.Add(new Point(145, 145)); horArr.Points.Add(new Point(150, 150)); horArr.Points.Add(new Point(145, 155)); horArr.Stroke = new SolidColorBrush(Colors.Black); LayoutRoot.Children.Add(horArr);
Фигуры удобны для создания самых простейших рисунков, дизайна, однако что-то более сложное и комплексное с их помощью сделать труднее. Поэтому для этих целей применяется клас Path. Он также, как и фигуры, наследуется от класса Shape, но представляет собой совокупность объединенных фигур. Класс Path имеет свойство Data, которое определяет объект Geometry - геометрический объект для отрисовки. Этот объект задает фигуру или совукупность фигур для отрисовки.
Класс Geometry - абстрактный, поэтому в качестве объекта используется один из производных классов:
LineGeometry представляет линию, эквивалент фигуры Line
RectangleGeometry представляет прямоугольник, эквивалент фигуры Rectangle
EllipseGeometry представляет эллипс, эквивалент фигуры Ellipse
PathGeometry представляет путь, образующий сложную геометрическую фигуру из простейших фигур
GeometryGroup создает фигуру, состоящую из нескольких объектов Geometry
Пример использования объектов Geometry:
<Path Stroke="Red" Fill="LightBlue"> <Path.Data> <GeometryGroup FillRule="EvenOdd"> <LineGeometry StartPoint="10,10" EndPoint="220,10" /> <EllipseGeometry Center="100,100" RadiusX="50" RadiusY="40" /> <RectangleGeometry Rect="120,100 80,20" RadiusX="5" RadiusY="5" /> </GeometryGroup> </Path.Data> </Path>
В данном случае свойство объекта GeometryGroup FillRule равно EvenOdd (значение по умолчанию), что позволяет создавать прозрачные перекрывающие поверхности. Если же установить FillRule="Nonzero", то перекрывающиеся поверхности геометрий будут окрашены также, как и остальные части пути.
Общим свойством для всех геометрий является свойство Transform, которое позволяет задавать трансформацию для данной геометрии (в данном случае мы осуществляем поворот):
<RectangleGeometry Rect="10,10 80,20" RadiusX="5" RadiusY="5"> <RectangleGeometry.Transform> <RotateTransform Angle="45" CenterX="20" CenterY="20" /> </RectangleGeometry.Transform> </RectangleGeometry>
PathGeometry содержит один или несколько компонентов PathFigure. Объект PathFigure в свою очередь формируется из сегментов. Все сегменты наследуются от класса PathSegment и бывают нескольких видов:
LineSegment задает отрезок прямой линии между двумя точками
ArcSegment задает дугу
BezierSegment задает кривую Безье
QuadraticBezierSegment задает квадратичную кривую Безье
PolyLineSegment задает сегмент из нескольких линий
PolyBezierSegment задает сегмент из нескольких кривых Безье
PolyQuadraticBezierSegment задает сегмент из нескольких квадратичных кривых Безье
Эти сегменты составляют свойство Segment объекта PathFigure. Кроме того, PathFigure имеет еще несколько важных свойств:
StartPoint - точка начала первой фигуры
IsClosed - если значение равно true, то первая и последняя точки (если они не совпадают) соединяются
IsFilled - если значение равно true, то площадь внутри пути окрашивается кистью, заданной свойством Fill у объекта Path
Пример использования:
<Path Stroke="Red"> <Path.Data> <PathGeometry> <PathFigure StartPoint="10,100"> <BezierSegment Point1="30,120" Point2="30,140" Point3="10 160" /> <LineSegment Point="40,100" /> <LineSegment Point="40,160" /> <LineSegment Point="60,100" /> <BezierSegment Point1="40,120" Point2="40 140" Point3="60,160" /> </PathFigure> <PathFigure StartPoint="20,130"> <LineSegment Point="50,130" /> </PathFigure> <PathFigure StartPoint="20,130"> <LineSegment Point="50,130" /> </PathFigure> <PathFigure StartPoint="100,100"> <PolyLineSegment Points="70,100 70,130" /> <PolyLineSegment Points="90,130 70,130 70,160,100,160" /> </PathFigure> <PathFigure StartPoint="110,100"> <PolyLineSegment Points="110,160 110,130 140,130 140,100 140,100 140,165" /> </PathFigure> <PathFigure StartPoint="180,100" IsClosed="True"> <ArcSegment Point="180,130" Size="70,20" SweepDirection="Counterclockwise" /> <PolyLineSegment Points="160,160 180,130 180,160" /> </PathFigure> </PathGeometry> </Path.Data> </Path>
Если переписать пример с координатной плоскостью с использованием объекта PathGeometry, то получится
PathGeometry pathGeom =new PathGeometry(); Path p =new Path(); LineSegment vertLS =new LineSegment(); PathFigure vertPF =new PathFigure(); vertPF.StartPoint = new Point(10, 150); vertLS.Point = new Point(10, 10); vertPF.Segments.Add(vertLS); pathGeom.Figures.Add(vertPF); LineSegment horLS =new LineSegment(); PathFigure horPF =new PathFigure(); horPF.StartPoint = new Point(10, 150); horLS.Point = new Point(150, 150); horPF.Segments.Add(horLS); pathGeom.Figures.Add(horPF); for(byte i = 2;i<15;i++) { PathFigure pf =new PathFigure(); pf.StartPoint = new Point(i * 10, 155); LineSegment a =new LineSegment(); a.Point = new Point(i * 10, 145); pf.Segments.Add(a); pathGeom.Figures.Add(pf); } for(byte i = 2;i<15;i++) { PathFigure pf =new PathFigure(); pf.StartPoint = new Point(5, i * 10); LineSegment a =new LineSegment(); a.Point = new Point(15, i * 10); pf.Segments.Add(a); pathGeom.Figures.Add(pf); } PolyLineSegment vertArr =new PolyLineSegment(); vertArr.Points = new PointCollection(); vertArr.Points.Add(new Point(10, 10)); vertArr.Points.Add(new Point(15, 15)); PathFigure vertArrF =new PathFigure(); vertArrF.StartPoint = new Point(5, 15); vertArrF.Segments.Add(vertArr); pathGeom.Figures.Add(vertArrF); PolyLineSegment horArr =new PolyLineSegment(); horArr.Points = new PointCollection(); horArr.Points.Add(new Point(150, 150)); horArr.Points.Add(new Point(145, 155)); PathFigure horArrF =new PathFigure(); horArrF.StartPoint = new Point(145, 145); horArrF.Segments.Add(horArr); pathGeom.Figures.Add(horArrF); p.Data = pathGeom; p.Stroke = new SolidColorBrush(Colors.Black); LayoutRoot.Children.Add(p);
Также принят упрощенный вариант записи фигур. Например, следующее описание фигуры
<Path Stroke="Red"> <Path.Data> <PathGeometry> <PathFigure StartPoint="20,170"> <LineSegment Point="50,170" /> </PathFigure> </PathGeometry> </Path.Data> </Path>
можно написать следубщим образом
<Path Data="M 20,170 L 50,170 Z" Stroke="Red" />
Что в данном случае означате сокращенная запись?
M x,y | Создает новый объект PathFigure и указывает на его начальную точку |
Z | Завершает фигуру и устанавливает свойство IsClosed в true. Если же не требуется завершать фигуру, то вместо Z употребляется буква M |
L x,y | Создает объект LineSegment до указанной точки |
A raduisX, radiusY, degrees, isLargArc, IaClockwize, x,y | Создает новый объект ArcSegment с соответствующими параметрами |
С x1,y1,x2,y2,x,y | Создает новый объект BezierSegment по указанным точкам |
Q x1,y1, x,y | Создает новый объект QuadraticBezierSegment по указанным точкам |
S x1,y1, x,y | Создает новый объект BezierSegment по указанным точкам |