Skip to main content

Shapes and geometries

Avalonia provides shape controls for drawing common 2D vector graphics and a geometry system for defining complex outlines used in paths, clipping, and hit testing.

Shape controls

Shape controls are visual elements you place directly in your XAML layout. They participate in layout and can receive pointer events.

Rectangle

<Rectangle Width="100" Height="60"
Fill="SteelBlue" Stroke="DarkBlue" StrokeThickness="2" />
PropertyDescription
RadiusX, RadiusYCorner rounding radius for rounded rectangles.
<Rectangle Width="100" Height="60" Fill="Coral"
RadiusX="10" RadiusY="10" />

Ellipse

<Ellipse Width="100" Height="80"
Fill="MediumPurple" Stroke="Indigo" StrokeThickness="2" />

A circle is an Ellipse with equal Width and Height.

Line

<Line StartPoint="0,0" EndPoint="200,100"
Stroke="Red" StrokeThickness="2" />

Polyline

Draws connected line segments without closing the shape:

<Polyline Points="0,0 50,50 100,0 150,50 200,0"
Stroke="Green" StrokeThickness="2" />

Polygon

Like Polyline but the shape is automatically closed:

<Polygon Points="50,0 100,100 0,100"
Fill="Gold" Stroke="DarkGoldenRod" StrokeThickness="1" />

Both Polyline and Polygon support a FillRule property that controls how self-intersecting shapes are filled:

  • EvenOdd (default): Alternates fill for overlapping regions, creating holes.
  • NonZero: Fills all enclosed regions regardless of overlap.
<Polygon Points="50,0 61,35 98,35 68,57 79,91 50,70 21,91 32,57 2,35 39,35"
Fill="Orange" FillRule="EvenOdd" />

Path

The most versatile shape control. Uses a Geometry to define its outline:

<!-- Using mini-language -->
<Path Data="M 10,10 L 100,10 L 100,100 Z"
Fill="LightBlue" Stroke="Navy" StrokeThickness="1" />

<!-- Using PathGeometry -->
<Path Fill="Orange">
<Path.Data>
<PathGeometry>
<PathFigure StartPoint="0,0" IsClosed="True">
<LineSegment Point="100,0" />
<LineSegment Point="100,100" />
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>

Common shape properties

All shapes inherit from Shape and share these properties:

PropertyDescription
FillThe brush that paints the interior.
StrokeThe brush that paints the outline.
StrokeThicknessThe thickness of the outline in device-independent pixels.
StrokeDashArrayA collection of double values defining a dashed line pattern.
StrokeDashOffsetThe offset into the dash pattern to start drawing.
StrokeLineCapThe cap style for line endpoints: Flat, Round, or Square.
StrokeJoinThe join style at corners: Miter, Bevel, or Round.
StrokeMiterLimitThe ratio limit at which a miter join is beveled. When the miter length divided by stroke thickness exceeds this value, the join switches from a sharp miter to a bevel. Default is 10. Only applies when StrokeJoin is Miter.
StretchHow the shape fills its allocated space: None, Fill, Uniform, UniformToFill.

Dashed lines

<Line StartPoint="0,0" EndPoint="200,0"
Stroke="Black" StrokeThickness="2"
StrokeDashArray="5,3" />

<Rectangle Width="150" Height="80" Fill="Transparent"
Stroke="Gray" StrokeThickness="1"
StrokeDashArray="4,2,1,2" />

Geometry types

Geometries define mathematical descriptions of 2D shapes. They are lighter than shape controls and are used by Path.Data, Clip, and OpacityMask.

RectangleGeometry

<Path Fill="LightCoral">
<Path.Data>
<RectangleGeometry Rect="0,0,100,60" />
</Path.Data>
</Path>

EllipseGeometry

<Path Fill="LightGreen">
<Path.Data>
<EllipseGeometry Center="50,40" RadiusX="50" RadiusY="40" />
</Path.Data>
</Path>

LineGeometry

<Path Stroke="Red" StrokeThickness="2">
<Path.Data>
<LineGeometry StartPoint="0,0" EndPoint="100,50" />
</Path.Data>
</Path>

PathGeometry

The most flexible geometry, composed of figures and segments:

<PathGeometry>
<PathFigure StartPoint="10,50" IsClosed="True" IsFilled="True">
<LineSegment Point="100,50" />
<ArcSegment Point="100,150" Size="50,50"
SweepDirection="Clockwise" />
<LineSegment Point="10,150" />
</PathFigure>
</PathGeometry>

Segment types

SegmentDescription
LineSegmentDraws a straight line to a point.
ArcSegmentDraws an elliptical arc.
BezierSegmentDraws a cubic Bezier curve (two control points).
QuadraticBezierSegmentDraws a quadratic Bezier curve (one control point).
PolyLineSegmentDraws a series of connected lines.
PolyBezierSegmentDraws a series of connected cubic Bezier curves. Each set of three points defines a control point, a second control point, and an endpoint.

CombinedGeometry

Combines two geometries using a set operation:

<Path Fill="CornflowerBlue">
<Path.Data>
<CombinedGeometry GeometryCombineMode="Exclude">
<CombinedGeometry.Geometry1>
<EllipseGeometry Center="50,50" RadiusX="50" RadiusY="50" />
</CombinedGeometry.Geometry1>
<CombinedGeometry.Geometry2>
<EllipseGeometry Center="80,50" RadiusX="50" RadiusY="50" />
</CombinedGeometry.Geometry2>
</CombinedGeometry>
</Path.Data>
</Path>
CombineModeResult
UnionArea covered by either geometry.
IntersectArea covered by both geometries.
ExcludeArea in the first geometry but not in the second.
XorArea covered by one geometry but not both.

GeometryGroup

Combines multiple geometries into a single geometry:

<Path Fill="Salmon" Stroke="DarkRed" StrokeThickness="1">
<Path.Data>
<GeometryGroup FillRule="EvenOdd">
<EllipseGeometry Center="50,50" RadiusX="50" RadiusY="50" />
<EllipseGeometry Center="50,50" RadiusX="25" RadiusY="25" />
</GeometryGroup>
</Path.Data>
</Path>

The FillRule determines how overlapping areas are filled:

  • EvenOdd: Alternates fill for overlapping regions (creates holes).
  • NonZero: Fills all enclosed regions.

Path mini-language

The Data property of Path accepts SVG-style path data as a string. This compact syntax is efficient for complex shapes.

Commands

CommandParametersDescription
M / mx,yMove to point (absolute / relative)
L / lx,yLine to point
H / hxHorizontal line
V / vyVertical line
C / cx1,y1 x2,y2 x,yCubic Bezier curve
S / sx2,y2 x,ySmooth cubic Bezier
Q / qx1,y1 x,yQuadratic Bezier curve
T / tx,ySmooth quadratic Bezier
A / arx,ry rotation large-arc sweep x,yElliptical arc
Z / zClose path

Uppercase commands use absolute coordinates, lowercase use relative coordinates.

Examples

<!-- Triangle -->
<Path Data="M 50,0 L 100,100 L 0,100 Z" Fill="Gold" />

<!-- Rounded rectangle path -->
<Path Data="M 10,0 H 90 A 10,10 0 0 1 100,10 V 50 A 10,10 0 0 1 90,60 H 10 A 10,10 0 0 1 0,50 V 10 A 10,10 0 0 1 10,0 Z"
Fill="LightSkyBlue" />

<!-- Heart shape -->
<Path Data="M 50,30 A 20,20 0 0 1 90,30 A 20,20 0 0 1 50,80 A 20,20 0 0 1 10,30 A 20,20 0 0 1 50,30 Z"
Fill="Red" />

<!-- Star -->
<Path Data="M 50,0 L 61,35 L 98,35 L 68,57 L 79,91 L 50,70 L 21,91 L 32,57 L 2,35 L 39,35 Z"
Fill="Orange" />

Building geometry from code

Use StreamGeometryContext to build geometry programmatically. Call StreamGeometry.Open() to get a context, then use its drawing methods to define figures:

var geometry = new StreamGeometry();

using (var ctx = geometry.Open())
{
ctx.BeginFigure(new Point(10, 50), isFilled: true);
ctx.LineTo(new Point(100, 50));
ctx.ArcTo(
new Point(100, 150),
new Size(50, 50),
rotationAngle: 0,
isLargeArc: false,
SweepDirection.Clockwise);
ctx.LineTo(new Point(10, 150));
ctx.EndFigure(isClosed: true);
}

StreamGeometryContext methods

MethodDescription
BeginFigure(Point, bool isFilled = true)Starts a new figure at the specified point. Set isFilled to false for an open, unfilled path.
LineTo(Point, bool isStroked = true)Draws a straight line to a point.
ArcTo(Point, Size, double, bool, SweepDirection, bool isStroked = true)Draws an elliptical arc to a point.
CubicBezierTo(Point, Point, Point, bool isStroked = true)Draws a cubic Bezier curve using two control points and an endpoint.
QuadraticBezierTo(Point, Point, bool isStroked = true)Draws a quadratic Bezier curve using one control point and an endpoint.
EndFigure(bool isClosed)Ends the current figure. Set isClosed to true to close the shape.

Set isStroked to false on any segment to skip drawing the outline for that segment while still including it in the geometry shape. This is useful for creating partially stroked paths.

using (var ctx = geometry.Open())
{
ctx.BeginFigure(new Point(0, 0), isFilled: false);
ctx.LineTo(new Point(50, 0)); // Stroked
ctx.LineTo(new Point(100, 0), isStroked: false); // Gap (not stroked)
ctx.LineTo(new Point(150, 0)); // Stroked
ctx.EndFigure(isClosed: false);
}

Geometry methods

All Geometry objects expose methods for hit testing and transformation:

MethodDescription
FillContains(Point)Returns true if the point is inside the filled area of the geometry.
StrokeContains(Pen, Point)Returns true if the point lies on the stroke of the geometry using the specified pen.
GetWidenedGeometry(Pen)Returns a new geometry representing the area that would be covered by stroking this geometry with the specified pen. Useful for creating outlined shapes.
GetFlattenedPathGeometry()Returns a simplified PathGeometry with curves approximated by line segments.
var ellipse = new EllipseGeometry { Center = new Point(50, 50), RadiusX = 40, RadiusY = 40 };
var pen = new Pen(Brushes.Black, 10);

// Get the outline of the stroked ellipse as a geometry
var outlined = ellipse.GetWidenedGeometry(pen);

Using geometries as resources

Define geometries as resources for reuse across your application:

<Application.Resources>
<StreamGeometry x:Key="CheckmarkIcon">M 4,8.5 L 8,12.5 L 16,4</StreamGeometry>
<StreamGeometry x:Key="CloseIcon">M 4,4 L 16,16 M 16,4 L 4,16</StreamGeometry>
</Application.Resources>

<Path Data="{StaticResource CheckmarkIcon}" Stroke="Green" StrokeThickness="2" />

StreamGeometry is a lightweight, immutable geometry optimized for performance. Use it for icon paths and other static shapes.

See also