Subclassing Shape (or more accurately, Path)

One of the more subtle improvements in Silverlight 4 is that we unsealed the Path class. That means you can write a class that behaves like a shape without re-implementing properties like Fill, Stroke, etc. — just subclass, set Path.Data to render what you want, and provide Measure/Arrange appropriate functionality. (Existing Shapes don’t all use the same measure/arrange logic)  Here’s a sample Triangle class:

    public class Triangle : Path
        public Triangle()

        private double lastWidth = 0;
        private double lastHeight = 0;
        private PathFigure figure;

        private void AddPoint(double x, double y)
            LineSegment segment = new LineSegment();
            segment.Point = new Point(x + 0.5 * StrokeThickness,
                y + 0.5 * StrokeThickness);

        private void CreatePathData(double width, double height)
            // in order to fit in our layout slot we need to reduce the size of the stroke
            height -= this.StrokeThickness;
            width -= this.StrokeThickness;

            // needed to avoid a layout loop
            if (lastWidth == width && lastHeight == height) return;
            lastWidth = width;
            lastHeight = height;

            var geometry = new PathGeometry();
            figure = new PathFigure();
            figure.StartPoint = new Point(0 + 0.5 * StrokeThickness, height + 0.5 * StrokeThickness);
            AddPoint(width, height);
            AddPoint(width / 2, 0);
            AddPoint(0, height);
            figure.IsClosed = true;
            this.Data = geometry;
        protected override Size MeasureOverride(Size availableSize)
            return availableSize;

        protected override Size ArrangeOverride(Size finalSize)
            CreatePathData(finalSize.Width, finalSize.Height);
            return finalSize;


Comments (3)

  1. AM says:

    Thanks for the tip. I was just getting into doing custom shapes in WPF and wanted to port the code over to Silverlight only to hit a bunch of limitations.

    I would have preferred to inherit from Geometry to create a custom geometry and then implement a shape that uses this new geometry but the Shape class in Silverlight does not allow you to override the protected DefiningGeometry property so it all went to waste.

  2. Jonathan says:

    "the Shape class in Silverlight does not allow you to override the protected DefiningGeometry property"

    I still haven’t found a good reason for this…  Anyone?

  3. Jonathan says:

    Also, there doesn’t seem to be a "Data" property for Path… 🙁